This commit is contained in:
Erik Joelsson 2013-02-18 10:48:51 +01:00
commit 2a904298d2
447 changed files with 51659 additions and 19100 deletions

View File

@ -198,3 +198,4 @@ a996b57e554198f4592a5f3c30f2f9f4075e545d jdk8-b70
57d5d954462831ac353a1f40d3bb05ddb4620952 jdk8-b74
4a67fdb752b7d6329d9be9c28d3f9d6cf7eb9a3c jdk8-b75
3a263052866137b645ab86498a43693ff5c19e69 jdk8-b76
b2fc8e31cecc35b76188e821d4c5dc0e0b74ac24 jdk8-b77

View File

@ -128,9 +128,9 @@ CORE_PKGS = \
java.text \
java.text.spi \
java.time \
java.time.temporal \
java.time.calendar \
java.time.chrono \
java.time.format \
java.time.temporal \
java.time.zone \
java.util \
java.util.concurrent \

View File

@ -255,7 +255,6 @@ JAVA_JAVA_java = \
java/util/SimpleTimeZone.java \
sun/util/calendar/ZoneInfo.java \
sun/util/calendar/ZoneInfoFile.java \
sun/util/calendar/TzIDOldMapping.java \
java/util/TooManyListenersException.java \
java/util/Comparator.java \
java/util/Collections.java \
@ -389,6 +388,7 @@ JAVA_JAVA_java = \
java/util/concurrent/locks/ReadWriteLock.java \
java/util/concurrent/locks/ReentrantLock.java \
java/util/concurrent/locks/ReentrantReadWriteLock.java \
java/util/concurrent/locks/StampedLock.java \
java/util/regex/Pattern.java \
java/util/regex/Matcher.java \
java/util/regex/MatchResult.java \

View File

@ -63,6 +63,7 @@ jprt.vm.default.test.targets= \
${jprt.my.test.target.set:TESTNAME=jvm98}
# Default jdk test targets (testset=default)
# NOTE: This does not match test/Makefile :: jdk_default
jprt.make.rule.default.test.targets= \
${jprt.my.test.target.set:TESTNAME=jdk_lang}, \
${jprt.my.test.target.set:TESTNAME=jdk_math}
@ -72,6 +73,7 @@ jprt.vm.core.test.targets= \
${jprt.vm.default.test.targets}
# Core jdk test targets (testset=core)
# NOTE: please keep this in sync with test/Makefile :: jdk_core
jprt.make.rule.core.test.targets= \
${jprt.make.rule.default.test.targets}, \
${jprt.my.test.target.set:TESTNAME=jdk_util}, \
@ -97,6 +99,7 @@ jprt.vm.all.test.targets= \
${jprt.my.test.target.set:TESTNAME=jbb_default}
# All jdk test targets (testset=all)
# NOTE: This does not match test/Makefile :: jdk_all
jprt.make.rule.all.test.targets= \
${jprt.make.rule.core.test.targets}, \
${jprt.my.test.target.set:TESTNAME=jdk_awt}, \

View File

@ -70,7 +70,7 @@ else
endif
# nio need to be compiled before awt to have all charsets ready
SUBDIRS = jar security javazic misc net nio text util launcher cldr tzdb
SUBDIRS = jar security misc net nio text util launcher cldr tzdb
ifdef BUILD_HEADLESS_ONLY
DISPLAY_LIBS = awt $(HEADLESS_SUBDIR)

View File

@ -33,11 +33,11 @@ include $(BUILDDIR)/common/Defs.gmk
# Time zone data file creation
TZDATA = ./tzdata/
TZDATA_VER = `$(GREP) '^tzdata' $(TZDATA)VERSION`
TZDATA_VER := $(shell $(GREP) '^tzdata' $(TZDATA)VERSION)
TZFILE = \
africa antarctica asia australasia europe northamerica \
pacificnew southamerica backward \
etcetera solar87 solar88 solar89 systemv
etcetera systemv
JDKTZDATA = ./tzdata_jdk/
JDKTZFILES = gmt jdk11_backward
TZFILES = \

View File

@ -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

View File

@ -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

View File

@ -43,9 +43,15 @@ BUILD_MANIFEST=true
#
TZDATA_DIR := ../javazic/tzdata
TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION))
TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera
TZFILE := \
africa antarctica asia australasia europe northamerica \
pacificnew southamerica backward etcetera \
gmt jdk11_backward
TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZFILE))
TZDB_JAR = tzdb.jar
#
@ -61,7 +67,7 @@ build: $(LIBDIR)/$(TZDB_JAR)
$(LIBDIR)/$(TZDB_JAR): $(TZFILES)
$(prep-target)
echo build tzdb from version $(TZDATA_VER)
$(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar -verbose \
$(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar \
-version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(LIBDIR) $(TZFILE)
clean clobber::

View File

@ -48,7 +48,6 @@ SUBDIRS = \
hasher_classes \
jarreorder \
jarsplit \
javazic \
jdwpgen \
makeclasslist \
strip_properties \

View File

@ -490,11 +490,16 @@ class Zoneinfo {
tz.addUsedRec(rrec);
usedZone = true;
}
} else {
} else { // fromTime == minTime
int save = rrec.getSave();
tz.addTransition(fromTime,
tz.addTransition(minTime,
tz.getOffsetIndex(gmtOffset),
tz.getDstOffsetIndex(0));
tz.addTransition(transition,
tz.getOffsetIndex(gmtOffset+save),
tz.getDstOffsetIndex(save));
tz.addUsedRec(rrec);
usedZone = true;
}

View File

@ -227,6 +227,7 @@ public final class TzdbZoneRulesCompiler {
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 @@ public final class TzdbZoneRulesCompiler {
}
// compile
String loopVersion = srcDir.getName();
String loopVersion = (srcDirs.size() == 1 && version != null)
? version : srcDir.getName();
TzdbZoneRulesCompiler compiler = new TzdbZoneRulesCompiler(loopVersion, srcFiles, verbose);
try {
// compile
@ -255,12 +257,13 @@ public final class TzdbZoneRulesCompiler {
if (verbose) {
System.out.println("Outputting file: " + dstFile);
}
outputFile(dstFile, loopVersion, builtZones);
outputFile(dstFile, loopVersion, builtZones, compiler.links);
// create totals
allBuiltZones.put(loopVersion, builtZones);
allRegionIds.addAll(builtZones.keySet());
allRules.addAll(builtZones.values());
allLinks.put(loopVersion, compiler.links);
} catch (Exception ex) {
System.out.println("Failed: " + ex.toString());
ex.printStackTrace();
@ -274,7 +277,7 @@ public final class TzdbZoneRulesCompiler {
if (verbose) {
System.out.println("Outputting combined file: " + dstFile);
}
outputFile(dstFile, allBuiltZones, allRegionIds, allRules);
outputFile(dstFile, allBuiltZones, allRegionIds, allRules, allLinks);
}
}
@ -283,12 +286,15 @@ public final class TzdbZoneRulesCompiler {
*/
private static void outputFile(File dstFile,
String version,
SortedMap<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 @@ public final class TzdbZoneRulesCompiler {
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 @@ public final class TzdbZoneRulesCompiler {
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 @@ public final class TzdbZoneRulesCompiler {
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 @@ public final class TzdbZoneRulesCompiler {
private int parseYear(String str, int defaultYear) {
if (YEAR.reset(str).matches()) {
if (YEAR.group("min") != null) {
return YEAR_MIN_VALUE;
//return YEAR_MIN_VALUE;
return 1900; // systemv has min
} else if (YEAR.group("max") != null) {
return YEAR_MAX_VALUE;
} else if (YEAR.group("only") != null) {
@ -742,16 +760,20 @@ public final class TzdbZoneRulesCompiler {
if (realRules == null) {
throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId + "' for '" + version + "'");
}
links.put(aliasId, realId);
}
builtZones.put(aliasId, realRules);
}
// remove UTC and GMT
builtZones.remove("UTC");
builtZones.remove("GMT");
builtZones.remove("GMT0");
//builtZones.remove("UTC");
//builtZones.remove("GMT");
//builtZones.remove("GMT0");
builtZones.remove("GMT+0");
builtZones.remove("GMT-0");
links.remove("GMT+0");
links.remove("GMT-0");
}
//-----------------------------------------------------------------------
@ -785,7 +807,6 @@ public final class TzdbZoneRulesCompiler {
boolean endOfDay;
/** The time of the cutover. */
TimeDefinition timeDefinition = TimeDefinition.WALL;
void adjustToFowards(int year) {
if (adjustForwards == false && dayOfMonth > 0) {
LocalDate adjustedDate = LocalDate.of(year, month, dayOfMonth).minusDays(6);

View File

@ -30,7 +30,7 @@ GENDATA_TZDB :=
#
TZDATA_DIR := $(JDK_TOPDIR)/make/sun/javazic/tzdata
TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION))
TZDATA_TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera
TZDATA_TZFILE := africa antarctica asia australasia europe northamerica pacificnew southamerica backward etcetera gmt jdk11_backward
TZDATA_TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZDATA_TZFILE))
GENDATA_TZDB_DST := $(JDK_OUTPUTDIR)/lib
@ -39,6 +39,6 @@ GENDATA_TZDB_JAR := tzdb.jar
$(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR) : $(TZDATA_TZFILES)
$(RM) $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)
echo building tzdb from version $(TZDATA_VER)
$(TOOL_TZDB) -verbose -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(GENDATA_TZDB_DST) $(TZDATA_TZFILE)
$(TOOL_TZDB) -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(GENDATA_TZDB_DST) $(TZDATA_TZFILE)
GENDATA_TZDB += $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)

View File

@ -34,7 +34,7 @@ GENDATA_TIMEZONE_TMP := $(JDK_OUTPUTDIR)/gendata_timezone
TZFILE0 := \
africa antarctica asia australasia europe northamerica \
pacificnew southamerica backward \
etcetera solar87 solar88 solar89 systemv
etcetera systemv
TZFILE1 := \
gmt jdk11_backward

View File

@ -44,9 +44,6 @@ GENDATA += $(BREAK_ITERATOR)
include GendataFontConfig.gmk
GENDATA += $(GENDATA_FONT_CONFIG)
include GendataTimeZone.gmk
GENDATA += $(GENDATA_TIMEZONE)
include GendataTZDB.gmk
GENDATA += $(GENDATA_TZDB)

View File

@ -103,9 +103,6 @@ TOOL_HASHER=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \
TOOL_JARSPLIT=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \
build.tools.jarsplit.JarSplit
TOOL_JAVAZIC=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \
build.tools.javazic.Main
TOOL_TZDB=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \
build.tools.tzdb.TzdbZoneRulesCompiler

View File

@ -30,6 +30,8 @@ import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.print.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.print.*;
import javax.print.attribute.PrintRequestAttributeSet;
@ -47,6 +49,8 @@ public class CPrinterJob extends RasterPrinterJob {
private static String sShouldNotReachHere = "Should not reach here.";
private volatile SecondaryLoop printingLoop;
private boolean noDefaultPrinter = false;
private static Font defaultFont;
@ -160,11 +164,22 @@ public class CPrinterJob extends RasterPrinterJob {
volatile boolean onEventThread;
@Override
protected void cancelDoc() throws PrinterAbortException {
super.cancelDoc();
if (printingLoop != null) {
printingLoop.exit();
}
}
private void completePrintLoop() {
Runnable r = new Runnable() { public void run() {
synchronized(this) {
performingPrinting = false;
}
if (printingLoop != null) {
printingLoop.exit();
}
}};
if (onEventThread) {
@ -219,17 +234,21 @@ public class CPrinterJob extends RasterPrinterJob {
onEventThread = true;
printingLoop = AccessController.doPrivileged(new PrivilegedAction<SecondaryLoop>() {
@Override
public SecondaryLoop run() {
return Toolkit.getDefaultToolkit()
.getSystemEventQueue()
.createSecondaryLoop();
}
});
try {
// Fire off the print rendering loop on the AppKit thread, and don't have
// it wait and block this thread.
if (printLoop(false, firstPage, lastPage)) {
// Fire off the EventConditional that will what until the condition is met,
// but will still process AWTEvent's as they occur.
new EventDispatchAccess() {
public boolean evaluate() {
return performingPrinting;
}
}.pumpEventsAndWait();
// Start a secondary loop on EDT until printing operation is finished or cancelled
printingLoop.enter();
}
} catch (Exception e) {
e.printStackTrace();
@ -253,6 +272,9 @@ public class CPrinterJob extends RasterPrinterJob {
performingPrinting = false;
notify();
}
if (printingLoop != null) {
printingLoop.exit();
}
}
// Normalize the collated, # copies, numPages, first/last pages. Need to

View File

@ -1,7 +1,7 @@
#
# This properties file is used to initialize the default
# java.awt.datatransfer.SystemFlavorMap. It contains the X11 platform-specific,
# default mappings between common X11 selection atoms and platform-independent
# java.awt.datatransfer.SystemFlavorMap. It contains the Mac OS X platform-specific,
# default mappings between common Mac OS X selection atoms and platform-independent
# MIME type strings, which will be converted into
# java.awt.datatransfer.DataFlavors.
#
@ -76,3 +76,5 @@ FILE_NAME=application/x-java-file-list;class=java.util.List
text/uri-list=application/x-java-file-list;class=java.util.List
PNG=image/x-java-image;class=java.awt.Image
JFIF=image/x-java-image;class=java.awt.Image
RICH_TEXT=text/rtf
HTML=text/html;charset=utf-8;eoln="\r\n";terminators=1

View File

@ -34,7 +34,7 @@ JNIEXPORT jlong JNICALL Java_com_apple_jobjc_SEL_getSelectorPtr
const char *selNameAsChars = (*env)->GetStringUTFChars(env, selName, JNI_FALSE);
const SEL sel = sel_registerName(selNameAsChars);
(*env)->ReleaseStringUTFChars(env, selName, selNameAsChars);
return ptr_to_jlong(sel);
return ptr_to_jlong((void*)sel);
}
JNIEXPORT jstring JNICALL Java_com_apple_jobjc_SEL_getSelectorName

View File

@ -383,31 +383,6 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj
}
}
/*
* Class: sun_lwawt_macosx_EventDispatchAccess
* Method: pumpEventsAndWait
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_EventDispatchAccess_pumpEventsAndWait
(JNIEnv *env, jobject eda)
{
static JNF_CLASS_CACHE(jc_Thread, "java/lang/Thread");
static JNF_STATIC_MEMBER_CACHE(jm_currentThread, jc_Thread, "currentThread", "()Ljava/lang/Thread;");
static JNF_CLASS_CACHE(jc_EventDispatchThread, "java/awt/EventDispatchThread");
static JNF_MEMBER_CACHE(jm_macosxGetConditional, jc_EventDispatchThread, "_macosxGetConditional", "(Ljava/lang/Object;)Ljava/awt/Conditional;");
static JNF_MEMBER_CACHE(jm_pumpEvents, jc_EventDispatchThread, "pumpEvents", "(Ljava/awt/Conditional;)V");
JNF_COCOA_DURING(env);
jobject thread = JNFCallStaticObjectMethod(env, jm_currentThread);
jobject conditional = JNFCallObjectMethod(env, thread, jm_macosxGetConditional, eda);
if (conditional != NULL) {
JNFCallVoidMethod(env, thread, jm_pumpEvents, conditional);
}
JNF_COCOA_HANDLE(env);
}
/*
* Class: sun_lwawt_macosx_CPrinterJob
* Method: abortDoc

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -106,8 +106,9 @@ inflate_file(int fd, zentry *entry, int *size_out)
*size_out = (int)entry->isize;
}
return (out);
} else
return (NULL);
}
free(in);
return (NULL);
}
static jboolean zip64_present = JNI_FALSE;
@ -563,7 +564,7 @@ JLI_ParseManifest(char *jarfile, manifest_info *info)
if ((fd = open(jarfile, O_RDONLY
#ifdef O_LARGEFILE
| O_LARGEFILE /* large file mode on solaris */
| O_LARGEFILE /* large file mode */
#endif
#ifdef O_BINARY
| O_BINARY /* use binary mode on windows */
@ -618,6 +619,9 @@ JLI_JarUnpackFile(const char *jarfile, const char *filename, int *size) {
void *data = NULL;
fd = open(jarfile, O_RDONLY
#ifdef O_LARGEFILE
| O_LARGEFILE /* large file mode */
#endif
#ifdef O_BINARY
| O_BINARY /* use binary mode on windows */
#endif
@ -661,6 +665,9 @@ JLI_ManifestIterate(const char *jarfile, attribute_closure ac, void *user_data)
int rc;
if ((fd = open(jarfile, O_RDONLY
#ifdef O_LARGEFILE
| O_LARGEFILE /* large file mode */
#endif
#ifdef O_BINARY
| O_BINARY /* use binary mode on windows */
#endif

View File

@ -52,16 +52,19 @@ import sun.misc.HexDumpEncoder;
* 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 @@ import sun.misc.HexDumpEncoder;
*
* <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 @@ import sun.misc.HexDumpEncoder;
*
* <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 @@ import sun.misc.HexDumpEncoder;
* <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 @@ import sun.misc.HexDumpEncoder;
* or through shared state.(Default is false)
* If set to true, credential must be obtained through cache, keytab,
* or shared state. Otherwise, authentication will fail.</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 @@ import sun.misc.HexDumpEncoder;
* 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 @@ import sun.misc.HexDumpEncoder;
* <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 @@ import sun.misc.HexDumpEncoder;
* <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 @@ import sun.misc.HexDumpEncoder;
* CallbackHandler to retrieve a new username
* and password, and another attempt to authenticate
* is made. If the authentication fails,
* the failure is reported back to the calling application
* the failure is reported back to the calling application</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 @@ import sun.misc.HexDumpEncoder;
* <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 @@ import sun.misc.HexDumpEncoder;
* <p> <code>useKeyTab</code> = true
* <code>keyTab</code>=&lt;keytabname&gt;
* <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 @@ import sun.misc.HexDumpEncoder;
* 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>=&lt;keytabname&gt;
* <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 @@ public class Krb5LoginModule implements LoginModule {
private KerberosTicket kerbTicket = null;
private KerberosKey[] kerbKeys = null;
private StringBuffer krb5PrincName = null;
private boolean unboundServer = false;
private char[] password = null;
private static final String NAME = "javax.security.auth.login.name";
@ -520,8 +536,6 @@ public class Krb5LoginModule implements LoginModule {
*/
public boolean login() throws LoginException {
int len;
validateConfiguration();
if (refreshKrb5Config) {
try {
if (debug) {
@ -544,6 +558,12 @@ public class Krb5LoginModule implements LoginModule {
}
}
validateConfiguration();
if (krb5PrincName != null && krb5PrincName.toString().equals("*")) {
unboundServer = true;
}
if (tryFirstPass) {
try {
attemptAuthentication(true);
@ -698,9 +718,17 @@ public class Krb5LoginModule implements LoginModule {
* (encKeys == null) to check.
*/
if (useKeyTab) {
ktab = (keyTabName == null)
? KeyTab.getInstance()
: KeyTab.getInstance(new File(keyTabName));
if (!unboundServer) {
KerberosPrincipal kp =
new KerberosPrincipal(principal.getName());
ktab = (keyTabName == null)
? KeyTab.getInstance(kp)
: KeyTab.getInstance(kp, new File(keyTabName));
} else {
ktab = (keyTabName == null)
? KeyTab.getUnboundInstance()
: KeyTab.getUnboundInstance(new File(keyTabName));
}
if (isInitiator) {
if (Krb5Util.keysFromJavaxKeyTab(ktab, principal).length
== 0) {
@ -939,6 +967,13 @@ public class Krb5LoginModule implements LoginModule {
("Configuration Error"
+ " - either useTicketCache should be "
+ " true or renewTGT should be false");
if (krb5PrincName != null && krb5PrincName.toString().equals("*")) {
if (isInitiator) {
throw new LoginException
("Configuration Error"
+ " - principal cannot be * when isInitiator is true");
}
}
}
private boolean isCurrent(Credentials creds)
@ -1052,7 +1087,10 @@ public class Krb5LoginModule implements LoginModule {
}
// Let us add the kerbClientPrinc,kerbTicket and KeyTab/KerbKey (if
// storeKey is true)
if (!princSet.contains(kerbClientPrinc)) {
// We won't add "*" as a KerberosPrincipal
if (!unboundServer &&
!princSet.contains(kerbClientPrinc)) {
princSet.add(kerbClientPrinc);
}

View File

@ -138,8 +138,7 @@ public final class Client extends NTLM {
domain = domainFromServer;
}
if (domain == null) {
throw new NTLMException(NTLMException.NO_DOMAIN_INFO,
"No domain info");
domain = "";
}
int flags = 0x88200 | (inputFlags & 3);

View File

@ -136,10 +136,10 @@ class NTLM {
int readInt(int offset) throws NTLMException {
try {
return internal[offset] & 0xff +
(internal[offset+1] & 0xff << 8) +
(internal[offset+2] & 0xff << 16) +
(internal[offset+3] & 0xff << 24);
return (internal[offset] & 0xff) +
((internal[offset+1] & 0xff) << 8) +
((internal[offset+2] & 0xff) << 16) +
((internal[offset+3] & 0xff) << 24);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
"Input message incorrect size");
@ -148,8 +148,8 @@ class NTLM {
int readShort(int offset) throws NTLMException {
try {
return internal[offset] & 0xff +
(internal[offset+1] & 0xff << 8);
return (internal[offset] & 0xff) +
((internal[offset+1] & 0xff << 8));
} catch (ArrayIndexOutOfBoundsException ex) {
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
"Input message incorrect size");

View File

@ -107,34 +107,6 @@ class EventDispatchThread extends Thread {
}
}
// MacOSX change:
// This was added because this class (and java.awt.Conditional) are package private.
// There are certain instances where classes in other packages need to block the
// AWTEventQueue while still allowing it to process events. This uses reflection
// to call back into the caller in order to remove dependencies.
//
// NOTE: This uses reflection in its implementation, so it is not for performance critical code.
//
// cond is an instance of sun.lwawt.macosx.EventDispatchAccess
//
private Conditional _macosxGetConditional(final Object cond) {
try {
return new Conditional() {
final Method evaluateMethod = Class.forName("sun.lwawt.macosx.EventDispatchAccess").getMethod("evaluate", null);
public boolean evaluate() {
try {
return ((Boolean)evaluateMethod.invoke(cond, null)).booleanValue();
} catch (Exception e) {
return false;
}
}
};
} catch (Exception e) {
return new Conditional() { public boolean evaluate() { return false; } };
}
}
void pumpEvents(Conditional cond) {
pumpEvents(ANY_EVENT, cond);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,7 +34,7 @@ import java.io.IOException;
*
* @since 1.5
*/
@FunctionalInterface
public interface Closeable extends AutoCloseable {
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,6 +35,7 @@ package java.io;
*
* @since 1.2
*/
@FunctionalInterface
public interface FileFilter {
/**
@ -46,5 +47,4 @@ public interface FileFilter {
* should be included
*/
boolean accept(File pathname);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -39,8 +39,8 @@ package java.io;
* @see java.io.File#list(java.io.FilenameFilter)
* @since JDK1.0
*/
public
interface FilenameFilter {
@FunctionalInterface
public interface FilenameFilter {
/**
* Tests if a specified file should be included in a file list.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,7 +34,7 @@ import java.io.IOException;
*
* @since 1.5
*/
@FunctionalInterface
public interface Flushable {
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,6 +31,7 @@ package java.lang;
* @author Josh Bloch
* @since 1.7
*/
@FunctionalInterface
public interface AutoCloseable {
/**
* Closes this resource, relinquishing any underlying resources.

View File

@ -3087,7 +3087,8 @@ public final
* @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 @@ public final
* @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 @@ public final
* @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();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -93,7 +93,7 @@ import java.util.*;
* @see java.util.Comparator
* @since 1.2
*/
@FunctionalInterface
public interface Comparable<T> {
/**
* Compares this object with the specified object for order. Returns a

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,6 +35,7 @@ import java.util.Iterator;
*
* @since 1.5
*/
@FunctionalInterface
public interface Iterable<T> {
/**

View File

@ -389,8 +389,9 @@ public class Package implements java.lang.reflect.AnnotatedElement {
* @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 @@ public class Package implements java.lang.reflect.AnnotatedElement {
* @throws NullPointerException {@inheritDoc}
* @since 1.8
*/
@Override
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) {
return getPackageInfo().getDeclaredAnnotation(annotationClass);
}
@ -412,8 +414,9 @@ public class Package implements java.lang.reflect.AnnotatedElement {
* @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);
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,7 +34,7 @@ import java.io.IOException;
*
* @since 1.5
*/
@FunctionalInterface
public interface Readable {
/**
@ -51,5 +51,4 @@ public interface Readable {
* @throws java.nio.ReadOnlyBufferException if cb is a read only buffer
*/
public int read(java.nio.CharBuffer cb) throws IOException;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -52,8 +52,8 @@ package java.lang;
* @see java.util.concurrent.Callable
* @since JDK1.0
*/
public
interface Runnable {
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1851,6 +1851,7 @@ class Thread implements Runnable {
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the

View File

@ -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 @@ public class AccessibleObject implements AnnotatedElement {
* @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 @@ public class AccessibleObject implements AnnotatedElement {
* @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 @@ public class AccessibleObject implements AnnotatedElement {
* @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);
}
/**

View File

@ -35,22 +35,43 @@ import java.lang.annotation.Annotation;
* arrays returned by accessors for array-valued enum members; it will
* have no affect on the arrays returned to other callers.
*
* <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 @@ public interface AnnotatedElement {
<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 @@ public interface AnnotatedElement {
* @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 @@ public interface AnnotatedElement {
*/
<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 @@ public interface AnnotatedElement {
* @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.

View File

@ -278,6 +278,10 @@ public abstract class Executable extends AccessibleObject
* this object. Returns an array of length 0 if the executable
* has no parameters.
*
* The parameters of the underlying executable do not necessarily
* have unique names, or names that are legal identifiers in the
* Java programming language (JLS 3.8).
*
* @return an array of {@code Parameter} objects representing all
* the parameters to the executable this object represents
*/
@ -445,7 +449,8 @@ public abstract class Executable extends AccessibleObject
* @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);

View File

@ -1029,7 +1029,8 @@ class Field extends AccessibleObject implements Member {
* @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);

View File

@ -342,13 +342,13 @@ class Modifier {
static final int SYNTHETIC = 0x00001000;
static final int ANNOTATION = 0x00002000;
static final int ENUM = 0x00004000;
static final int SYNTHESIZED = 0x00010000;
static final int MANDATED = 0x00008000;
static boolean isSynthetic(int mod) {
return (mod & SYNTHETIC) != 0;
}
static boolean isSynthesized(int mod) {
return (mod & SYNTHESIZED) != 0;
static boolean isMandated(int mod) {
return (mod & MANDATED) != 0;
}
/**

View File

@ -44,7 +44,7 @@ public final class Parameter implements AnnotatedElement {
private final String name;
private final int modifiers;
private final Executable executable;
private int index;
private final int index;
/**
* Package-private constructor for {@code Parameter}.
@ -95,9 +95,14 @@ public final class Parameter implements AnnotatedElement {
}
/**
* Returns a string representation of the parameter's modifiers,
* its attributes, its type, its name, and a trailing ... if it is
* a variadic parameter.
* Returns a string describing this parameter. The format is the
* modifiers for the parameter, if any, in canonical order as
* recommended by <cite>The Java&trade; 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 @@ public final class Parameter implements AnnotatedElement {
sb.append(typename);
sb.append(" ");
sb.append(name);
sb.append(getName());
return sb.toString();
}
@ -143,11 +148,23 @@ public final class Parameter implements AnnotatedElement {
}
/**
* Returns the name of the parameter represented by this
* {@code Parameter} object.
* Returns the name of the parameter. The names of the parameters
* of a single executable must all the be distinct. When names
* from the originating source are available, they are returned.
* Otherwise, an implementation of this method is free to create a
* name of this parameter, subject to the unquiness requirments.
*/
public String getName() {
return name;
// As per the spec, if a parameter has no name, return argX,
// where x is the index.
//
// Note: spec updates now outlaw empty strings as parameter
// names. The .equals("") is for compatibility with current
// JVM behavior. It may be removed at some point.
if(name == null || name.equals(""))
return "arg" + index;
else
return name;
}
/**
@ -190,20 +207,21 @@ public final class Parameter implements AnnotatedElement {
private transient volatile Class<?> parameterClassCache = null;
/**
* Returns {@code true} if this parameter is a synthesized
* construct; returns {@code false} otherwise.
* Returns {@code true} if this parameter is implicitly declared
* in source code; returns {@code false} otherwise.
*
* @return true if and only if this parameter is a synthesized
* construct as defined by
* <cite>The Java&trade; Language Specification</cite>.
* @return true if and only if this parameter is implicitly
* declared as defined by <cite>The Java&trade; 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 @@ public final class Parameter implements AnnotatedElement {
* {@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 @@ public final class Parameter implements AnnotatedElement {
/**
* @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);
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -117,8 +117,7 @@ import java.io.IOException;
*/
public interface DirectoryStream<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 @@ public interface DirectoryStream<T>
*
* @since 1.7
*/
@FunctionalInterface
public static interface Filter<T> {
/**
* Decides if the given directory entry should be accepted or filtered.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,7 +34,7 @@ package java.nio.file;
* @see FileSystem#getPathMatcher
* @see Files#newDirectoryStream(Path,String)
*/
@FunctionalInterface
public interface PathMatcher {
/**
* Tells if given path matches this matcher's pattern.

View File

@ -218,6 +218,150 @@ public class KeyStore {
public ProtectionParameter getProtectionParameter();
}
/**
* Configuration data that specifies the keystores in a keystore domain.
* A keystore domain is a collection of keystores that are presented as a
* single logical keystore. The configuration data is used during
* {@code KeyStore}
* {@link #load(KeyStore.LoadStoreParameter) load} and
* {@link #store(KeyStore.LoadStoreParameter) store} operations.
* <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.
*

View File

@ -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 @@ public class Date extends java.util.Date {
int firstDash;
int secondDash;
Date d = null;
if (s == null) {
throw new java.lang.IllegalArgumentException();
}
@ -255,4 +257,50 @@ public class Date extends java.util.Date {
* compatibility.
*/
static final long serialVersionUID = 1511598038487230103L;
/**
* Obtains an instance of {@code Date} from a {@link LocalDate} object
* with the same year, month and day of month value as the given
* {@code LocalDate}.
* <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();
}
}

View File

@ -190,7 +190,17 @@ public enum JDBCType implements SQLType {
/**
* Identifies the generic SQL type {@code REF_CURSOR}.
*/
REF_CURSOR(Types.REF_CURSOR);
REF_CURSOR(Types.REF_CURSOR),
/**
* Identifies the generic SQL type {@code TIME_WITH_TIMEZONE}.
*/
TIME_WITH_TIMEZONE(Types.TIME_WITH_TIMEZONE),
/**
* Identifies the generic SQL type {@code TIMESTAMP_WITH_TIMEZONE}.
*/
TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE);
/**
* The Integer value for the JDBCType. It maps to a value in

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -421,4 +421,38 @@ public interface SQLInput {
*/
RowId readRowId() throws SQLException;
//--------------------------JDBC 4.2 -----------------------------
/**
* Reads the next attribute in the stream and returns it as an
* {@code Object} in the Java programming language. The
* actual type of the object returned is determined by the specified
* Java data type, and any customizations present in this
* stream's type map.
*
* <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();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -272,7 +272,7 @@ package java.sql;
* Otherwise, it calls the <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 @@ package java.sql;
*/
void writeSQLXML(SQLXML x) throws SQLException;
//--------------------------JDBC 4.2 -----------------------------
/**
* Writes to the stream the data contained in the given object. The
* object will be converted to the specified targetSqlType
* before being sent to the stream.
*<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();
}
}

View File

@ -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 @@ public class Time extends java.util.Date {
* compatibility.
*/
static final long serialVersionUID = 8397324403548013681L;
/**
* Obtains an instance of {@code Time} from a {@link LocalTime} object
* with the same hour, minute and second time value as the given
* {@code LocalTime}.
*
* @param time a {@code LocalTime} to convert
* @return a {@code Time} object
* @exception NullPointerException if {@code time} is null
* @since 1.8
*/
@SuppressWarnings("deprecation")
public static Time valueOf(LocalTime time) {
return new Time(time.getHour(), time.getMinute(), time.getSecond());
}
/**
* Converts this {@code Time} object to a {@code LocalTime}.
* <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();
}
}

View File

@ -25,6 +25,8 @@
package java.sql;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.StringTokenizer;
/**
@ -485,7 +487,6 @@ public class Timestamp extends java.util.Date {
}
}
return i;
}
/**
@ -530,4 +531,89 @@ public class Timestamp extends java.util.Date {
static final long serialVersionUID = 2745179027874758501L;
private static final int MILLIS_PER_SECOND = 1000;
/**
* Obtains an instance of {@code Timestamp} from a {@code LocalDateTime}
* object, with the same year, month, day of month, hours, minutes,
* seconds and nanos date-time value as the provided {@code LocalDateTime}.
* <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);
}
}

View File

@ -319,6 +319,24 @@ public class Types {
*/
public static final int REF_CURSOR = 2012;
/**
* The constant in the Java programming language, sometimes referred to
* as a type code, that identifies the generic SQL type
* {@code TIME WITH TIMEZONE}.
*
* @since 1.8
*/
public static final int TIME_WITH_TIMEZONE = 2013;
/**
* The constant in the Java programming language, sometimes referred to
* as a type code, that identifies the generic SQL type
* {@code TIMESTAMP WITH TIMEZONE}.
*
* @since 1.8
*/
public static final int TIMESTAMP_WITH_TIMEZONE = 2014;
// Prevent instantiation
private Types() {}
}

View File

@ -377,60 +377,57 @@ public abstract class Clock {
* an instant on the time-line rather than a raw millisecond value.
* This method is provided to allow the use of the clock in high performance use cases
* where the creation of an object would be unacceptable.
* <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 @@ public abstract class Clock {
return System.currentTimeMillis();
}
@Override
public Instant instant() {
return Instant.ofEpochMilli(millis());
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SystemClock) {
return zone.equals(((SystemClock) obj).zone);

View File

@ -170,8 +170,9 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
/**
* 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 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
/**
* 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 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* @param locale the locale to use, not null
* @return the text value of the day-of-week, not null
*/
public String getText(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).print(this);
public String getDisplayName(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).format(this);
}
//-----------------------------------------------------------------------
@ -232,7 +234,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* All other {@code ChronoField} instances will return false.
* <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 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
if (field instanceof ChronoField) {
return field == DAY_OF_WEEK;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
@ -260,7 +262,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <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 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* 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 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* 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 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------

View File

@ -61,10 +61,14 @@
*/
package java.time;
import static java.time.LocalTime.NANOS_PER_SECOND;
import static java.time.LocalTime.SECONDS_PER_DAY;
import static java.time.temporal.ChronoField.INSTANT_SECONDS;
import static java.time.LocalTime.SECONDS_PER_HOUR;
import static java.time.LocalTime.SECONDS_PER_MINUTE;
import static java.time.temporal.ChronoField.NANO_OF_SECOND;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.NANOS;
import static java.time.temporal.ChronoUnit.SECONDS;
import java.io.DataInput;
import java.io.DataOutput;
@ -79,17 +83,23 @@ import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdder;
import java.time.temporal.TemporalSubtractor;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A duration between two instants on the time-line.
* A time-based amount of time, such as '34.5 seconds'.
* <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 @@ import java.util.Objects;
* The range of a duration requires the storage of a number larger than a {@code long}.
* To achieve this, the class stores a {@code long} representing seconds and an {@code int}
* representing nanosecond-of-second, which will always be between 0 and 999,999,999.
* The model is of a directed duration, meaning that the duration may be negative.
* <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 @@ import java.util.Objects;
* @since 1.8
*/
public final class Duration
implements TemporalAdder, TemporalSubtractor, Comparable<Duration>, Serializable {
implements TemporalAmount, Comparable<Duration>, Serializable {
/**
* Constant for a duration of zero.
@ -122,14 +133,17 @@ public final class Duration
* Serialization version.
*/
private static final long serialVersionUID = 3078945930695997490L;
/**
* Constant for nanos per second.
*/
private static final int NANOS_PER_SECOND = 1000_000_000;
/**
* Constant for nanos per second.
*/
private static final BigInteger BI_NANOS_PER_SECOND = BigInteger.valueOf(NANOS_PER_SECOND);
/**
* The pattern for parsing.
*/
private final static Pattern PATTERN =
Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)D)?" +
"(T(?:([-+]?[0-9]+)H)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)(?:[.,]([0-9]{0,9}))?S)?)?",
Pattern.CASE_INSENSITIVE);
/**
* The number of seconds in the duration.
@ -143,7 +157,53 @@ public final class Duration
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Duration} from a number of seconds.
* Obtains a {@code Duration} representing a number of standard 24 hour days.
* <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 @@ public final class Duration
}
/**
* Obtains an instance of {@code Duration} from a number of seconds
* and an adjustment in nanoseconds.
* Obtains a {@code Duration} representing a number of seconds and an
* adjustment in nanoseconds.
* <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 final class Duration
*/
public static Duration ofSeconds(long seconds, long nanoAdjustment) {
long secs = Math.addExact(seconds, Math.floorDiv(nanoAdjustment, NANOS_PER_SECOND));
int nos = (int)Math.floorMod(nanoAdjustment, NANOS_PER_SECOND);
int nos = (int) Math.floorMod(nanoAdjustment, NANOS_PER_SECOND);
return create(secs, nos);
}
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Duration} from a number of milliseconds.
* Obtains a {@code Duration} representing a number of milliseconds.
* <p>
* The seconds and nanoseconds are extracted from the specified milliseconds.
*
@ -200,7 +260,7 @@ public final class Duration
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Duration} from a number of nanoseconds.
* Obtains a {@code Duration} representing a number of nanoseconds.
* <p>
* The seconds and nanoseconds are extracted from the specified nanoseconds.
*
@ -219,53 +279,7 @@ public final class Duration
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Duration} from a number of standard length minutes.
* <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 @@ public final class Duration
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Duration} representing the duration between two instants.
* Obtains a {@code Duration} representing the duration between two instants.
* <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);
}
String numberText = text.subSequence(2, len - 1).toString().replace(',', '.');
if (numberText.charAt(0) == '+') {
throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2);
}
int dot = numberText.indexOf('.');
try {
if (dot == -1) {
// no decimal places
if (numberText.startsWith("-0")) {
throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2);
Matcher matcher = PATTERN.matcher(text);
if (matcher.matches()) {
// check for letter T but no time sections
if ("T".equals(matcher.group(3)) == false) {
boolean negate = "-".equals(matcher.group(1));
String dayMatch = matcher.group(2);
String hourMatch = matcher.group(4);
String minuteMatch = matcher.group(5);
String secondMatch = matcher.group(6);
String fractionMatch = matcher.group(7);
if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) {
long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days");
long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours");
long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes");
long seconds = parseNumber(text, secondMatch, 1, "seconds");
int nanos = parseFraction(text, fractionMatch, seconds < 0 ? -1 : 1);
try {
return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos);
} catch (ArithmeticException ex) {
throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0).initCause(ex);
}
}
return create(Long.parseLong(numberText), 0);
}
// decimal places
boolean negative = false;
if (numberText.charAt(0) == '-') {
negative = true;
}
long secs = Long.parseLong(numberText.substring(0, dot));
numberText = numberText.substring(dot + 1);
len = numberText.length();
if (len == 0 || len > 9 || numberText.charAt(0) == '-' || numberText.charAt(0) == '+') {
throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2);
}
int nanos = Integer.parseInt(numberText);
switch (len) {
case 1:
nanos *= 100000000;
break;
case 2:
nanos *= 10000000;
break;
case 3:
nanos *= 1000000;
break;
case 4:
nanos *= 100000;
break;
case 5:
nanos *= 10000;
break;
case 6:
nanos *= 1000;
break;
case 7:
nanos *= 100;
break;
case 8:
nanos *= 10;
break;
}
return negative ? ofSeconds(secs, -nanos) : create(secs, nanos);
} catch (ArithmeticException | NumberFormatException ex) {
throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2, ex);
}
throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0);
}
private static long parseNumber(CharSequence text, String parsed, int multiplier, String errorText) {
// regex limits to [-+]?[0-9]+
if (parsed == null) {
return 0;
}
try {
long val = Long.parseLong(parsed);
return Math.multiplyExact(val, multiplier);
} catch (NumberFormatException | ArithmeticException ex) {
throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex);
}
}
private static int parseFraction(CharSequence text, String parsed, int negate) {
// regex limits to [0-9]{0,9}
if (parsed == null || parsed.length() == 0) {
return 0;
}
try {
parsed = (parsed + "000000000").substring(0, 9);
return Integer.parseInt(parsed) * negate;
} catch (NumberFormatException | ArithmeticException ex) {
throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex);
}
}
private static Duration create(boolean negate, long daysAsSecs, long hoursAsSecs, long minsAsSecs, long secs, int nanos) {
long seconds = Math.addExact(daysAsSecs, Math.addExact(hoursAsSecs, Math.addExact(minsAsSecs, secs)));
if (negate) {
return ofSeconds(seconds, nanos).negated();
}
return ofSeconds(seconds, nanos);
}
//-----------------------------------------------------------------------
@ -420,6 +463,56 @@ public final class Duration
this.nanos = nanos;
}
//-----------------------------------------------------------------------
/**
* Gets the value of the requested unit.
* <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.
@ -434,19 +527,6 @@ public final class Duration
return (seconds | nanos) == 0;
}
/**
* Checks if this duration is positive, excluding zero.
* <p>
* A {@code Duration} represents a directed distance between two points on
* the time-line and can therefore be positive, zero or negative.
* This method checks whether the length is greater than zero.
*
* @return true if this duration has a total length greater than zero
*/
public boolean isPositive() {
return seconds >= 0 && ((seconds | nanos) != 0);
}
/**
* Checks if this duration is negative, excluding zero.
* <p>
@ -497,6 +577,39 @@ public final class Duration
return nanos;
}
//-----------------------------------------------------------------------
/**
* 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.
@ -551,6 +664,48 @@ public final class Duration
}
//-----------------------------------------------------------------------
/**
* 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>
@ -650,6 +805,52 @@ public final class Duration
}
//-----------------------------------------------------------------------
/**
* 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>
@ -716,8 +917,7 @@ public final class Duration
*
* @param divisor the value to divide the duration by, positive or negative, not zero
* @return a {@code Duration} based on this duration divided by the specified divisor, not null
* @throws ArithmeticException if the divisor is zero
* @throws ArithmeticException if numeric overflow occurs
* @throws ArithmeticException if the divisor is zero or if numeric overflow occurs
*/
public Duration dividedBy(long divisor) {
if (divisor == 0) {
@ -794,15 +994,15 @@ public final class Duration
* with this duration added.
* <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 @@ public final class Duration
*/
@Override
public Temporal addTo(Temporal temporal) {
long instantSecs = temporal.getLong(INSTANT_SECONDS);
long instantNanos = temporal.getLong(NANO_OF_SECOND);
instantSecs = Math.addExact(instantSecs, seconds);
instantNanos = Math.addExact(instantNanos, nanos);
instantSecs = Math.addExact(instantSecs, Math.floorDiv(instantNanos, NANOS_PER_SECOND));
instantNanos = Math.floorMod(instantNanos, NANOS_PER_SECOND);
return temporal.with(INSTANT_SECONDS, instantSecs).with(NANO_OF_SECOND, instantNanos);
if (seconds != 0) {
temporal = temporal.plus(seconds, SECONDS);
}
if (nanos != 0) {
temporal = temporal.plus(nanos, NANOS);
}
return temporal;
}
/**
@ -829,15 +1029,15 @@ public final class Duration
* with this duration subtracted.
* <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,16 +1048,59 @@ public final class Duration
*/
@Override
public Temporal subtractFrom(Temporal temporal) {
long instantSecs = temporal.getLong(INSTANT_SECONDS);
long instantNanos = temporal.getLong(NANO_OF_SECOND);
instantSecs = Math.subtractExact(instantSecs, seconds);
instantNanos = Math.subtractExact(instantNanos, nanos);
instantSecs = Math.addExact(instantSecs, Math.floorDiv(instantNanos, NANOS_PER_SECOND));
instantNanos = Math.floorMod(instantNanos, NANOS_PER_SECOND);
return temporal.with(INSTANT_SECONDS, instantSecs).with(NANO_OF_SECOND, instantNanos);
if (seconds != 0) {
temporal = temporal.minus(seconds, SECONDS);
}
if (nanos != 0) {
temporal = temporal.minus(nanos, NANOS);
}
return temporal;
}
//-----------------------------------------------------------------------
/**
* Gets the number of minutes in this duration.
* <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>
@ -887,7 +1130,7 @@ public final class Duration
* @throws ArithmeticException if numeric overflow occurs
*/
public long toNanos() {
long millis = Math.multiplyExact(seconds, 1000_000_000);
long millis = Math.multiplyExact(seconds, NANOS_PER_SECOND);
millis = Math.addExact(millis, nanos);
return millis;
}
@ -911,30 +1154,6 @@ public final class Duration
return nanos - otherDuration.nanos;
}
/**
* Checks if this duration is greater than the specified {@code Duration}.
* <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 @@ public final class Duration
//-----------------------------------------------------------------------
/**
* A string representation of this duration using ISO-8601 seconds
* based representation, such as {@code PT12.345S}.
* based representation, such as {@code PT8H6M12.345S}.
* <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);

View File

@ -61,6 +61,7 @@
*/
package java.time;
import static java.time.LocalTime.NANOS_PER_SECOND;
import static java.time.LocalTime.SECONDS_PER_DAY;
import static java.time.LocalTime.SECONDS_PER_HOUR;
import static java.time.LocalTime.SECONDS_PER_MINUTE;
@ -76,18 +77,17 @@ import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.format.DateTimeFormatters;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdder;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalSubtractor;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.util.Objects;
@ -225,10 +225,6 @@ public final class Instant
* Serialization version.
*/
private static final long serialVersionUID = -665713676816604388L;
/**
* Constant for nanos per second.
*/
private static final int NANOS_PER_SECOND = 1000_000_000;
/**
* The number of seconds from the epoch of 1970-01-01T00:00:00Z.
@ -333,8 +329,9 @@ public final class Instant
/**
* Obtains an instance of {@code Instant} from a temporal object.
* <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 @@ public final class Instant
* {@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 @@ public final class Instant
* 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 @@ public final class Instant
if (field instanceof ChronoField) {
return field == INSTANT_SECONDS || field == NANO_OF_SECOND || field == MICRO_OF_SECOND || field == MILLI_OF_SECOND;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
@ -447,7 +444,7 @@ public final class Instant
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <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 @@ public final class Instant
* 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 @@ public final class Instant
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return range(field).checkValidIntValue(field.doGet(this), field);
return range(field).checkValidIntValue(field.getFrom(this), field);
}
/**
@ -511,7 +508,7 @@ public final class Instant
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <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 @@ public final class Instant
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
@ -565,7 +562,7 @@ public final class Instant
/**
* Returns an adjusted copy of this instant.
* <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 @@ public final class Instant
/**
* 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 @@ public final class Instant
* 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 @@ public final class Instant
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doWith(this, newValue);
return field.adjustInto(this, newValue);
}
//-----------------------------------------------------------------------
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
* Returns a copy of this {@code Instant} truncated to the specified unit.
* <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 @@ public final class Instant
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
return unit.doPlus(this, amountToAdd);
return unit.addTo(this, amountToAdd);
}
//-----------------------------------------------------------------------
@ -751,19 +854,47 @@ public final class Instant
//-----------------------------------------------------------------------
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
* Returns a copy of this instant with the specified amount subtracted.
* <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 @@ public final class Instant
return (R) NANOS;
}
// inline TemporalAccessor.super.query(query) as an optimization
if (query == Queries.chrono() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
if (query == Queries.chronology() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
return null;
}
return query.queryFrom(this);
@ -945,7 +1076,7 @@ public final class Instant
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
return unit.between(this, endInstant).getAmount();
return unit.between(this, endInstant);
}
private long nanosUntil(Instant end) {
@ -957,6 +1088,43 @@ public final class Instant
return Math.subtractExact(end.seconds, seconds);
}
//-----------------------------------------------------------------------
/**
* Combines this instant with an offset to create an {@code OffsetDateTime}.
* <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
@ -1059,13 +1227,13 @@ public final class Instant
/**
* 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);
}
// -----------------------------------------------------------------------

View File

@ -80,26 +80,22 @@ import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.format.DateTimeBuilder;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Era;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatters;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Era;
import java.time.temporal.ISOChrono;
import java.time.temporal.OffsetDate;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdder;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalSubtractor;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.time.temporal.Year;
import java.time.zone.ZoneOffsetTransition;
import java.time.zone.ZoneRules;
import java.util.Objects;
@ -131,7 +127,7 @@ import java.util.Objects;
* @since 1.8
*/
public final class LocalDate
implements Temporal, TemporalAdjuster, ChronoLocalDate<ISOChrono>, Serializable {
implements Temporal, TemporalAdjuster, ChronoLocalDate<LocalDate>, Serializable {
/**
* The minimum supported {@code LocalDate}, '-999999999-01-01'.
@ -216,7 +212,7 @@ public final class LocalDate
*/
public static LocalDate now(Clock clock) {
Objects.requireNonNull(clock, "clock");
// inline OffsetDate factory to avoid creating object and InstantProvider checks
// inline to avoid creating object and Instant checks
final Instant now = clock.instant(); // called once
ZoneOffset offset = clock.getZone().getRules().getOffset(now);
long epochSec = now.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later
@ -228,14 +224,15 @@ public final class LocalDate
/**
* Obtains an instance of {@code LocalDate} from a year, month and day.
* <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 @@ public final class LocalDate
/**
* 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 @@ public final class LocalDate
/**
* 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 @@ public final class LocalDate
/**
* 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 @@ public final class LocalDate
/**
* 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 @@ public final class LocalDate
* @throws DateTimeException if unable to convert to a {@code LocalDate}
*/
public static LocalDate from(TemporalAccessor temporal) {
if (temporal instanceof LocalDate) {
return (LocalDate) temporal;
} else if (temporal instanceof LocalDateTime) {
return ((LocalDateTime) temporal).getDate();
} else if (temporal instanceof ZonedDateTime) {
return ((ZonedDateTime) temporal).getDate();
}
// handle builder as a special case
if (temporal instanceof DateTimeBuilder) {
DateTimeBuilder builder = (DateTimeBuilder) temporal;
LocalDate date = builder.extract(LocalDate.class);
if (date != null) {
return date;
}
}
try {
return ofEpochDay(temporal.getLong(EPOCH_DAY));
} catch (DateTimeException ex) {
throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass(), ex);
LocalDate date = temporal.query(Queries.localDate());
if (date == null) {
throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass());
}
return date;
}
//-----------------------------------------------------------------------
@ -378,14 +365,14 @@ public final class LocalDate
* Obtains an instance of {@code LocalDate} from a text string such as {@code 2007-12-03}.
* <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 @@ public final class LocalDate
* @throws DateTimeException if the day-of-month is invalid for the month-year
*/
private static LocalDate create(int year, Month month, int dayOfMonth) {
if (dayOfMonth > 28 && dayOfMonth > month.length(ISOChrono.INSTANCE.isLeapYear(year))) {
if (dayOfMonth > 28 && dayOfMonth > month.length(IsoChronology.INSTANCE.isLeapYear(year))) {
if (dayOfMonth == 29) {
throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year");
} else {
@ -435,7 +422,7 @@ public final class LocalDate
private static LocalDate resolvePreviousValid(int year, int month, int day) {
switch (month) {
case 2:
day = Math.min(day, ISOChrono.INSTANCE.isLeapYear(year) ? 29 : 28);
day = Math.min(day, IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28);
break;
case 4:
case 6:
@ -469,8 +456,6 @@ public final class LocalDate
* {@link #get(TemporalField) get} methods will throw an exception.
* <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 @@ public final class LocalDate
* 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 @@ public final class LocalDate
* 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 @@ public final class LocalDate
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doRange(this);
return field.rangeRefinedBy(this);
}
/**
@ -558,7 +543,7 @@ public final class LocalDate
* 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 @@ public final class LocalDate
* 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 @@ public final class LocalDate
}
return get0(field);
}
return field.doGet(this);
return field.getFrom(this);
}
private int get0(TemporalField field) {
@ -638,7 +623,7 @@ public final class LocalDate
/**
* 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 @@ public final class LocalDate
* @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 @@ public final class LocalDate
* 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 @@ public final class LocalDate
* 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 @@ public final class LocalDate
*/
@Override // override for Javadoc and performance
public boolean isLeapYear() {
return ISOChrono.INSTANCE.isLeapYear(year);
return IsoChronology.INSTANCE.isLeapYear(year);
}
/**
@ -819,7 +804,7 @@ public final class LocalDate
/**
* 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 @@ public final class LocalDate
* 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 @@ public final class LocalDate
/**
* 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 @@ public final class LocalDate
* 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 @@ public final class LocalDate
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doWith(this, newValue);
return field.adjustInto(this, newValue);
}
//-----------------------------------------------------------------------
@ -1033,8 +1018,8 @@ public final class LocalDate
*
* @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 @@ public final class LocalDate
*
* @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 @@ public final class LocalDate
//-----------------------------------------------------------------------
/**
* 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 @@ public final class LocalDate
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
return unit.doPlus(this, amountToAdd);
return unit.addTo(this, amountToAdd);
}
//-----------------------------------------------------------------------
@ -1221,40 +1275,47 @@ public final class LocalDate
//-----------------------------------------------------------------------
/**
* 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 @@ public final class LocalDate
* @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 @@ public final class LocalDate
* 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 @@ public final class LocalDate
}
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 @@ public final class LocalDate
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 @@ public final class LocalDate
}
/**
* 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 @@ public final class LocalDate
}
/**
* 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 @@ public final class LocalDate
}
/**
* 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 @@ public final class LocalDate
}
/**
* 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.
* <p>
* This instance is immutable and unaffected by this method call.
* This returns an {@code OffsetDateTime} formed from this date at the specified time.
* All possible combinations of date and time are valid.
*
* @param offset the offset to combine with, not null
* @return the offset date formed from this date and the specified offset, not null
* @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 OffsetDate atOffset(ZoneOffset offset) {
return OffsetDate.of(this, offset);
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 returns a {@code LocalDateTime} formed from this date at the time of
* midnight, 00:00, at the start of this date.
*
* @return the local date-time of midnight at the start of this date, not null
*/
public LocalDateTime atStartOfDay() {
return LocalDateTime.of(this, LocalTime.MIDNIGHT);
}
/**
@ -1582,8 +1708,6 @@ public final class LocalDate
* <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 @@ public final class LocalDate
* 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 @@ public final class LocalDate
* 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

View File

@ -70,6 +70,7 @@ import static java.time.LocalTime.NANOS_PER_HOUR;
import static java.time.LocalTime.NANOS_PER_MINUTE;
import static java.time.LocalTime.NANOS_PER_SECOND;
import static java.time.LocalTime.SECONDS_PER_DAY;
import static java.time.temporal.ChronoField.NANO_OF_SECOND;
import java.io.DataInput;
import java.io.DataOutput;
@ -77,21 +78,19 @@ import java.io.IOException;
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 @@ import java.util.Objects;
* @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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
* @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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
* @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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
* @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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
* @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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
* @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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
* @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 @@ public final class LocalDateTime
* @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 @@ public final class LocalDateTime
/**
* 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 @@ public final class LocalDateTime
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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
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 @@ public final class LocalDateTime
* @return the date part of this date-time, not null
*/
@Override
public LocalDate getDate() {
public LocalDate toLocalDate() {
return date;
}
@ -667,7 +686,7 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
* @return the time part of this date-time, not null
*/
@Override
public LocalTime getTime() {
public LocalTime toLocalTime() {
return time;
}
@ -797,7 +816,7 @@ public final class LocalDateTime
/**
* 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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
/**
* 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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
return with(date.with(field, newValue), time);
}
}
return field.doWith(this, newValue);
return field.adjustInto(this, newValue);
}
//-----------------------------------------------------------------------
@ -935,8 +954,8 @@ public final class LocalDateTime
*
* @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 @@ public final class LocalDateTime
*
* @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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
//-----------------------------------------------------------------------
/**
* 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 @@ public final class LocalDateTime
}
return with(date.plus(amountToAdd, unit), time);
}
return unit.doPlus(this, amountToAdd);
return unit.addTo(this, amountToAdd);
}
//-----------------------------------------------------------------------
@ -1237,40 +1272,47 @@ public final class LocalDateTime
//-----------------------------------------------------------------------
/**
* 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 @@ public final class LocalDateTime
* @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 @@ public final class LocalDateTime
* 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 @@ public final class LocalDateTime
}
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 @@ public final class LocalDateTime
}
/**
* 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 @@ public final class LocalDateTime
* {@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 @@ public final class LocalDateTime
}
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 @@ public final class LocalDateTime
* 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

View File

@ -76,23 +76,17 @@ import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.format.DateTimeBuilder;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatters;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.ChronoZonedDateTime;
import java.time.temporal.OffsetTime;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdder;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.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 final class LocalTime
*/
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 @@ public final class LocalTime
// 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 @@ public final class LocalTime
/**
* 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 @@ public final class LocalTime
/**
* 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 @@ public final class LocalTime
/**
* 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
@ -365,31 +355,10 @@ public final class LocalTime
return create(hours, minutes, (int) secondOfDay, 0);
}
/**
* Obtains an instance of {@code LocalTime} from a second-of-day value, with
* associated nanos of second.
* <p>
* This factory may return a cached value, but applications must not rely on this.
*
* @param secondOfDay the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1}
* @param nanoOfSecond the nano-of-second, from 0 to 999,999,999
* @return the local time, not null
* @throws DateTimeException if the either input value is invalid
*/
public static LocalTime ofSecondOfDay(long secondOfDay, int nanoOfSecond) {
SECOND_OF_DAY.checkValidValue(secondOfDay);
NANO_OF_SECOND.checkValidValue(nanoOfSecond);
int hours = (int) (secondOfDay / SECONDS_PER_HOUR);
secondOfDay -= hours * SECONDS_PER_HOUR;
int minutes = (int) (secondOfDay / SECONDS_PER_MINUTE);
secondOfDay -= minutes * SECONDS_PER_MINUTE;
return create(hours, minutes, (int) secondOfDay, nanoOfSecond);
}
/**
* Obtains an instance of {@code LocalTime} from a nanos-of-day value.
* <p>
* This factory may return a cached value, but applications must not rely on this.
* 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 @@ public final class LocalTime
/**
* 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 @@ public final class LocalTime
* @throws DateTimeException if unable to convert to a {@code LocalTime}
*/
public static LocalTime from(TemporalAccessor temporal) {
if (temporal instanceof LocalTime) {
return (LocalTime) temporal;
} else if (temporal instanceof ChronoLocalDateTime) {
return ((ChronoLocalDateTime) temporal).getTime();
} else if (temporal instanceof ChronoZonedDateTime) {
return ((ChronoZonedDateTime) temporal).getTime();
}
// handle builder as a special case
if (temporal instanceof DateTimeBuilder) {
DateTimeBuilder builder = (DateTimeBuilder) temporal;
LocalTime time = builder.extract(LocalTime.class);
if (time != null) {
return time;
}
}
try {
return ofNanoOfDay(temporal.getLong(NANO_OF_DAY));
} catch (DateTimeException ex) {
throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass(), ex);
LocalTime time = temporal.query(Queries.localTime());
if (time == null) {
throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass());
}
return time;
}
//-----------------------------------------------------------------------
@ -450,14 +406,14 @@ public final class LocalTime
* 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 @@ public final class LocalTime
* 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 @@ public final class LocalTime
if (field instanceof ChronoField) {
return ((ChronoField) field).isTimeField();
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
@ -568,7 +524,7 @@ public final class LocalTime
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.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 @@ public final class LocalTime
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.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 @@ public final class LocalTime
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.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 @@ public final class LocalTime
}
return get0(field);
}
return field.doGet(this);
return field.getFrom(this);
}
private int get0(TemporalField field) {
@ -711,7 +667,7 @@ public final class LocalTime
/**
* 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 @@ public final class LocalTime
/**
* 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 @@ public final class LocalTime
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doWith(Temporal, long)}
* 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 @@ public final class LocalTime
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doWith(this, newValue);
return field.adjustInto(this, newValue);
}
//-----------------------------------------------------------------------
@ -924,8 +880,10 @@ public final class LocalTime
* 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 final class LocalTime
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 @@ public final class LocalTime
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
return unit.doPlus(this, amountToAdd);
return unit.addTo(this, amountToAdd);
}
//-----------------------------------------------------------------------
@ -1107,40 +1107,47 @@ public final class LocalTime
//-----------------------------------------------------------------------
/**
* 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 @@ public final class LocalTime
@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 @@ public final class LocalTime
* 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 @@ public final class LocalTime
}
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 @@ public final class LocalTime
}
/**
* 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 @@ public final class LocalTime
* 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 final class LocalTime
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.print(this);
return formatter.format(this);
}
//-----------------------------------------------------------------------

View File

@ -64,11 +64,11 @@ package java.time;
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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
/**
* 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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
/**
* 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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* @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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* 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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* 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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* 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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* 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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
@ -554,8 +554,8 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
@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 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
*/
@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());

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
@ -70,14 +70,19 @@ import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.time.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;
/**
@ -198,8 +203,8 @@ public final class MonthDay
* @param month the month-of-year to represent, not null
* @param dayOfMonth the day-of-month to represent, from 1 to 31
* @return the month-day, not null
* @throws DateTimeException if the value of any field is out of range
* @throws DateTimeException if the day-of-month is invalid for the month
* @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");
@ -224,8 +229,8 @@ public final class MonthDay
* @param month the month-of-year to represent, from 1 (January) to 12 (December)
* @param dayOfMonth the day-of-month to represent, from 1 to 31
* @return the month-day, not null
* @throws DateTimeException if the value of any field is out of range
* @throws DateTimeException if the day-of-month is invalid for the month
* @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);
@ -235,8 +240,9 @@ public final class MonthDay
/**
* Obtains an instance of {@code MonthDay} from a temporal object.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code MonthDay}.
* 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.
@ -254,7 +260,7 @@ public final class MonthDay
return (MonthDay) 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), temporal.get(DAY_OF_MONTH));
@ -314,8 +320,6 @@ public final class MonthDay
* {@link #get(TemporalField) get} methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this date-time.
* The supported fields are:
* <ul>
* <li>{@code MONTH_OF_YEAR}
@ -324,7 +328,7 @@ public final class MonthDay
* 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.
*
@ -336,7 +340,7 @@ public final class MonthDay
if (field instanceof ChronoField) {
return field == MONTH_OF_YEAR || field == DAY_OF_MONTH;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
@ -353,7 +357,7 @@ public final class MonthDay
* 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.
*
@ -385,7 +389,7 @@ public final class MonthDay
* 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.
*
@ -412,7 +416,7 @@ public final class MonthDay
* 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.
*
@ -431,10 +435,24 @@ public final class MonthDay
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
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>
@ -444,6 +462,7 @@ public final class MonthDay
* provides the {@link Month#getValue() int value}.
*
* @return the month-of-year, not null
* @see #getMonthValue()
*/
public Month getMonth() {
return Month.of(month);
@ -524,8 +543,8 @@ public final class MonthDay
*
* @param dayOfMonth the day-of-month to set in the return month-day, from 1 to 31
* @return a {@code MonthDay} based on this month-day with the requested day, not null
* @throws DateTimeException if the day-of-month value is invalid
* @throws DateTimeException if the day-of-month is invalid for the month
* @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) {
@ -556,8 +575,8 @@ public final class MonthDay
@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;
}
return TemporalAccessor.super.query(query);
}
@ -591,7 +610,7 @@ public final class MonthDay
*/
@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");
}
temporal = temporal.with(MONTH_OF_YEAR, month);
@ -600,9 +619,10 @@ public final class MonthDay
//-----------------------------------------------------------------------
/**
* Returns a date formed from this month-day at the specified year.
* 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>
* This combines this month-day and the specified year to form a {@code LocalDate}.
* A month-day of February 29th will be adjusted to February 28th in the resulting
* date if the year is not a leap year.
* <p>
@ -610,7 +630,7 @@ public final class MonthDay
*
* @param year the year to use, from MIN_YEAR to MAX_YEAR
* @return the local date formed from this month-day and the specified year, not null
* @see Year#atMonthDay(MonthDay)
* @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);
@ -626,6 +646,7 @@ public final class MonthDay
* @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) {
@ -705,7 +726,7 @@ public final class MonthDay
* Outputs this month-day as a {@code String} using the formatter.
* <p>
* This month-day will be passed to the formatter
* {@link DateTimeFormatter#print(TemporalAccessor) print method}.
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted month-day string, not null
@ -713,7 +734,7 @@ public final class MonthDay
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.print(this);
return formatter.format(this);
}
//-----------------------------------------------------------------------
@ -721,7 +742,7 @@ public final class MonthDay
* Writes the object using a
* <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
* <pre>
* out.writeByte(6); // identifies this as a Year
* out.writeByte(13); // identifies this as a MonthDay
* out.writeByte(month);
* out.writeByte(day);
* </pre>

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time;
import static java.time.temporal.ChronoField.EPOCH_DAY;
import static java.time.temporal.ChronoField.INSTANT_SECONDS;
@ -73,20 +73,20 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.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.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;
@ -151,7 +151,7 @@ public final class OffsetDateTime
public int compare(OffsetDateTime datetime1, OffsetDateTime datetime2) {
int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond());
if (cmp == 0) {
cmp = Long.compare(datetime1.getTime().toNanoOfDay(), datetime2.getTime().toNanoOfDay());
cmp = Long.compare(datetime1.toLocalTime().toNanoOfDay(), datetime2.toLocalTime().toNanoOfDay());
}
return cmp;
}
@ -253,18 +253,34 @@ public final class OffsetDateTime
}
/**
* Obtains an instance of {@code OffsetDateTime} from a {@code ZonedDateTime}.
* 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 same local date-time and offset as
* the zoned date-time. The result will have the same instant as the input.
* 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 zonedDateTime the zoned date-time to convert from, not null
* @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 result exceeds the supported range
* @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(ZonedDateTime zonedDateTime) {
Objects.requireNonNull(zonedDateTime, "zonedDateTime");
return new OffsetDateTime(zonedDateTime.getDateTime(), zonedDateTime.getOffset());
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);
}
//-----------------------------------------------------------------------
@ -293,11 +309,16 @@ public final class OffsetDateTime
/**
* Obtains an instance of {@code OffsetDateTime} from a temporal object.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code OffsetDateTime}.
* 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 extracts and combines {@code LocalDateTime} and {@code ZoneOffset}.
* If that fails it will try to extract and combine {@code Instant} and {@code ZoneOffset}.
* 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}.
@ -330,14 +351,14 @@ public final class OffsetDateTime
* such as {@code 2007-12-03T10:15:30+01:00}.
* <p>
* The string must represent a valid date-time and is parsed using
* {@link java.time.format.DateTimeFormatters#isoOffsetDateTime()}.
* {@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, DateTimeFormatters.isoOffsetDateTime());
return parse(text, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}
/**
@ -425,7 +446,7 @@ public final class OffsetDateTime
* 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.
*
@ -434,7 +455,7 @@ public final class OffsetDateTime
*/
@Override
public boolean isSupported(TemporalField field) {
return field instanceof ChronoField || (field != null && field.doIsSupported(this));
return field instanceof ChronoField || (field != null && field.isSupportedBy(this));
}
/**
@ -451,7 +472,7 @@ public final class OffsetDateTime
* 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.
*
@ -467,7 +488,7 @@ public final class OffsetDateTime
}
return dateTime.range(field);
}
return field.doRange(this);
return field.rangeRefinedBy(this);
}
/**
@ -486,7 +507,7 @@ public final class OffsetDateTime
* 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.
*
@ -520,7 +541,7 @@ public final class OffsetDateTime
* 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.
*
@ -538,7 +559,7 @@ public final class OffsetDateTime
}
return dateTime.getLong(field);
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
@ -611,7 +632,7 @@ public final class OffsetDateTime
*
* @return the local date-time part of this date-time, not null
*/
public LocalDateTime getDateTime() {
public LocalDateTime toLocalDateTime() {
return dateTime;
}
@ -624,8 +645,8 @@ public final class OffsetDateTime
*
* @return the date part of this date-time, not null
*/
public LocalDate getDate() {
return dateTime.getDate();
public LocalDate toLocalDate() {
return dateTime.toLocalDate();
}
/**
@ -634,7 +655,7 @@ public final class OffsetDateTime
* 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
*/
@ -719,8 +740,8 @@ public final class OffsetDateTime
*
* @return the time part of this date-time, not null
*/
public LocalTime getTime() {
return dateTime.getTime();
public LocalTime toLocalTime() {
return dateTime.toLocalTime();
}
/**
@ -763,7 +784,7 @@ public final class OffsetDateTime
/**
* Returns an adjusted copy of this date-time.
* <p>
* This returns a new {@code OffsetDateTime}, based on this one, with the date-time adjusted.
* 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>
@ -772,7 +793,7 @@ public final class OffsetDateTime
* 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>
@ -821,7 +842,7 @@ public final class OffsetDateTime
/**
* Returns a copy of this date-time with the specified field set to a new value.
* <p>
* This returns a new {@code OffsetDateTime}, based on this one, with the value
* 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
@ -849,7 +870,7 @@ public final class OffsetDateTime
* 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>
@ -873,7 +894,7 @@ public final class OffsetDateTime
}
return with(dateTime.with(field, newValue), offset);
}
return field.doWith(this, newValue);
return field.adjustInto(this, newValue);
}
//-----------------------------------------------------------------------
@ -916,8 +937,8 @@ public final class OffsetDateTime
*
* @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31
* @return an {@code OffsetDateTime} based on this date-time with the requested day, not null
* @throws DateTimeException if the day-of-month value is invalid
* @throws DateTimeException if the day-of-month is invalid for the month-year
* @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);
@ -931,8 +952,8 @@ public final class OffsetDateTime
*
* @param dayOfYear the day-of-year to set in the result, from 1 to 365-366
* @return an {@code OffsetDateTime} based on this date with the requested day, not null
* @throws DateTimeException if the day-of-year value is invalid
* @throws DateTimeException if the day-of-year is invalid for the year
* @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);
@ -1008,8 +1029,10 @@ public final class OffsetDateTime
* 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>
* The offset does not affect the calculation and will be the same in the result.
* <p>
@ -1025,49 +1048,60 @@ public final class OffsetDateTime
//-----------------------------------------------------------------------
/**
* 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 java.time.Period} but may be any other type implementing
* the {@link TemporalAdder} interface.
* The calculation is delegated to the specified adjuster, which typically calls
* back to {@link #plus(long, TemporalUnit)}.
* The offset is not part of the calculation and will be unchanged in the result.
* This 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 adder the adder to use, not null
* @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(TemporalAdder adder) {
return (OffsetDateTime) adder.addTo(this);
public OffsetDateTime plus(TemporalAmount amountToAdd) {
return (OffsetDateTime) 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 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 period to add, not null
* @return an {@code OffsetDateTime} based on this date-time with the specified period added, not null
* @throws DateTimeException if the unit cannot be added to this type
* @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.doPlus(this, amountToAdd);
return unit.addTo(this, amountToAdd);
}
//-----------------------------------------------------------------------
@ -1211,41 +1245,47 @@ public final class OffsetDateTime
//-----------------------------------------------------------------------
/**
* 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 java.time.Period} but may be any other type implementing
* the {@link TemporalSubtractor} interface.
* The calculation is delegated to the specified adjuster, which typically calls
* back to {@link #minus(long, TemporalUnit)}.
* The offset is not part of the calculation and will be unchanged in the result.
* This 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 subtractor the subtractor to use, not null
* @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(TemporalSubtractor subtractor) {
return (OffsetDateTime) subtractor.subtractFrom(this);
public OffsetDateTime minus(TemporalAmount amountToSubtract) {
return (OffsetDateTime) 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.
* The offset is not part of the calculation and will be unchanged in the result.
* 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 period to subtract, not null
* @return an {@code OffsetDateTime} based on this date-time with the specified period subtracted, not null
* @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) {
@ -1413,14 +1453,22 @@ public final class OffsetDateTime
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.chrono()) {
return (R) getDate().getChrono();
if (query == Queries.offset() || query == Queries.zone()) {
return (R) getOffset();
} else if (query == Queries.zoneId()) {
return null;
} else if (query == Queries.localDate()) {
return (R) toLocalDate();
} else if (query == Queries.localTime()) {
return (R) toLocalTime();
} else if (query == Queries.chronology()) {
return (R) IsoChronology.INSTANCE;
} else if (query == Queries.precision()) {
return (R) NANOS;
} else if (query == Queries.offset() || query == Queries.zone()) {
return (R) getOffset();
}
return Temporal.super.query(query);
// inline TemporalAccessor.super.query(query) as an optimization
// non-JDK classes are not permitted to make this optimization
return query.queryFrom(this);
}
/**
@ -1453,8 +1501,8 @@ public final class OffsetDateTime
public Temporal adjustInto(Temporal temporal) {
return temporal
.with(OFFSET_SECONDS, getOffset().getTotalSeconds())
.with(EPOCH_DAY, getDate().toEpochDay())
.with(NANO_OF_DAY, getTime().toNanoOfDay());
.with(EPOCH_DAY, toLocalDate().toEpochDay())
.with(NANO_OF_DAY, toLocalTime().toNanoOfDay());
}
/**
@ -1476,14 +1524,15 @@ public final class OffsetDateTime
* For example, the period in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z
* will only be one month as it is one minute short of two months.
* <p>
* This method operates in association with {@link TemporalUnit#between}.
* The result of this method is a {@code long} representing the amount of
* the specified unit. By contrast, the result of {@code between} is an
* object that can be used directly in addition/subtraction:
* 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},
@ -1516,22 +1565,21 @@ public final class OffsetDateTime
end = end.withOffsetSameInstant(offset);
return dateTime.periodUntil(end.dateTime, unit);
}
return unit.between(this, endDateTime).getAmount();
return unit.between(this, endDateTime);
}
//-----------------------------------------------------------------------
/**
* Returns a zoned date-time formed from the instant represented by this
* date-time and the specified zone ID.
* Combines this date-time with a time-zone to create a {@code ZonedDateTime}
* ensuring that the result has the same instant.
* <p>
* This returns a {@code ZonedDateTime} formed from this date-time and the specified time-zone.
* This conversion will ignore the visible local date-time and use the underlying instant instead.
* This avoids any problems with local time-line gaps or overlaps.
* The result might have different values for fields such as hour, minute an even day.
* <p>
* To attempt to retain the values of the fields, use {@link #atZoneSimilarLocal(ZoneId)}.
* To use the offset as the zone ID, use {@link #toZonedDateTime()}.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param zone the time-zone to use, not null
* @return the zoned date-time formed from this date-time, not null
@ -1541,7 +1589,11 @@ public final class OffsetDateTime
}
/**
* Returns a zoned date-time formed from this date-time and the specified zone ID.
* Combines this date-time with a time-zone to create a {@code ZonedDateTime}
* trying to keep the same local date and time.
* <p>
* This returns a {@code ZonedDateTime} formed from this date-time and the specified time-zone.
* Where possible, the result will have the same local date-time as this object.
* <p>
* Time-zone rules, such as daylight savings, mean that not every time on the
* local time-line exists. If the local date-time is in a gap or overlap according to
@ -1556,8 +1608,6 @@ public final class OffsetDateTime
* To create a zoned date-time at the same instant irrespective of the local time-line,
* use {@link #atZoneSameInstant(ZoneId)}.
* To use the offset as the zone ID, use {@link #toZonedDateTime()}.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param zone the time-zone to use, not null
* @return the zoned date-time formed from this date and the earliest valid time for the zone, not null
@ -1567,17 +1617,6 @@ public final class OffsetDateTime
}
//-----------------------------------------------------------------------
/**
* Converts this date-time to an {@code OffsetDate}.
* <p>
* This returns an offset date with the same local date and offset.
*
* @return an OffsetDate representing the date and offset, not null
*/
public OffsetDate toOffsetDate() {
return OffsetDate.of(dateTime.getDate(), offset);
}
/**
* Converts this date-time to an {@code OffsetTime}.
* <p>
@ -1586,7 +1625,7 @@ public final class OffsetDateTime
* @return an OffsetTime representing the time and offset, not null
*/
public OffsetTime toOffsetTime() {
return OffsetTime.of(dateTime.getTime(), offset);
return OffsetTime.of(dateTime.toLocalTime(), offset);
}
/**
@ -1606,6 +1645,9 @@ public final class OffsetDateTime
/**
* Converts this date-time to an {@code Instant}.
* <p>
* This returns an {@code Instant} representing the same point on the
* time-line as this date-time.
*
* @return an {@code Instant} representing the same instant, not null
*/
@ -1653,13 +1695,13 @@ public final class OffsetDateTime
@Override
public int compareTo(OffsetDateTime other) {
if (getOffset().equals(other.getOffset())) {
return getDateTime().compareTo(other.getDateTime());
return toLocalDateTime().compareTo(other.toLocalDateTime());
}
int cmp = Long.compare(toEpochSecond(), other.toEpochSecond());
if (cmp == 0) {
cmp = getTime().getNano() - other.getTime().getNano();
cmp = toLocalTime().getNano() - other.toLocalTime().getNano();
if (cmp == 0) {
cmp = getDateTime().compareTo(other.getDateTime());
cmp = toLocalDateTime().compareTo(other.toLocalDateTime());
}
}
return cmp;
@ -1680,7 +1722,7 @@ public final class OffsetDateTime
long thisEpochSec = toEpochSecond();
long otherEpochSec = other.toEpochSecond();
return thisEpochSec > otherEpochSec ||
(thisEpochSec == otherEpochSec && getTime().getNano() > other.getTime().getNano());
(thisEpochSec == otherEpochSec && toLocalTime().getNano() > other.toLocalTime().getNano());
}
/**
@ -1697,7 +1739,7 @@ public final class OffsetDateTime
long thisEpochSec = toEpochSecond();
long otherEpochSec = other.toEpochSecond();
return thisEpochSec < otherEpochSec ||
(thisEpochSec == otherEpochSec && getTime().getNano() < other.getTime().getNano());
(thisEpochSec == otherEpochSec && toLocalTime().getNano() < other.toLocalTime().getNano());
}
/**
@ -1712,7 +1754,7 @@ public final class OffsetDateTime
*/
public boolean isEqual(OffsetDateTime other) {
return toEpochSecond() == other.toEpochSecond() &&
getTime().getNano() == other.getTime().getNano();
toLocalTime().getNano() == other.toLocalTime().getNano();
}
//-----------------------------------------------------------------------
@ -1774,7 +1816,7 @@ public final class OffsetDateTime
* 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
@ -1782,7 +1824,7 @@ public final class OffsetDateTime
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.print(this);
return formatter.format(this);
}
//-----------------------------------------------------------------------
@ -1790,7 +1832,7 @@ public final class OffsetDateTime
* Writes the object using a
* <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
* <pre>
* out.writeByte(3); // identifies this as a OffsetDateTime
* out.writeByte(10); // identifies this as a OffsetDateTime
* out.writeObject(dateTime);
* out.writeObject(offset);
* </pre>

View File

@ -59,14 +59,14 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time;
import static java.time.LocalTime.NANOS_PER_HOUR;
import static java.time.LocalTime.NANOS_PER_MINUTE;
import static java.time.LocalTime.NANOS_PER_SECOND;
import static java.time.LocalTime.SECONDS_PER_DAY;
import static java.time.temporal.ChronoField.NANO_OF_DAY;
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
import static java.time.temporal.ChronoLocalDateTimeImpl.NANOS_PER_HOUR;
import static java.time.temporal.ChronoLocalDateTimeImpl.NANOS_PER_MINUTE;
import static java.time.temporal.ChronoLocalDateTimeImpl.NANOS_PER_SECOND;
import static java.time.temporal.ChronoLocalDateTimeImpl.SECONDS_PER_DAY;
import static java.time.temporal.ChronoUnit.NANOS;
import java.io.IOException;
@ -75,16 +75,19 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatters;
import java.time.format.DateTimeParseException;
import java.time.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.Objects;
@ -202,6 +205,29 @@ public final class OffsetTime
return new OffsetTime(time, offset);
}
/**
* Obtains an instance of {@code OffsetTime} from an hour, minute, second and nanosecond.
* <p>
* This creates an offset time with the four 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 LocalTime} has two additional convenience variants of the
* equivalent factory method taking fewer arguments.
* They are not provided here to reduce the footprint of the API.
*
* @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 time, not null
* @throws DateTimeException if the value of any field is out of range
*/
public static OffsetTime of(int hour, int minute, int second, int nanoOfSecond, ZoneOffset offset) {
return new OffsetTime(LocalTime.of(hour, minute, second, nanoOfSecond), offset);
}
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code OffsetTime} from an {@code Instant} and zone ID.
@ -223,12 +249,9 @@ public final class OffsetTime
Objects.requireNonNull(zone, "zone");
ZoneRules rules = zone.getRules();
ZoneOffset offset = rules.getOffset(instant);
long secsOfDay = instant.getEpochSecond() % SECONDS_PER_DAY;
secsOfDay = (secsOfDay + offset.getTotalSeconds()) % SECONDS_PER_DAY;
if (secsOfDay < 0) {
secsOfDay += SECONDS_PER_DAY;
}
LocalTime time = LocalTime.ofSecondOfDay(secsOfDay, instant.getNano());
long localSecond = instant.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later
int secsOfDay = (int) Math.floorMod(localSecond, SECONDS_PER_DAY);
LocalTime time = LocalTime.ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + instant.getNano());
return new OffsetTime(time, offset);
}
@ -236,10 +259,14 @@ public final class OffsetTime
/**
* Obtains an instance of {@code OffsetTime} from a temporal object.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code OffsetTime}.
* 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 OffsetTime}.
* <p>
* The conversion extracts and combines {@code LocalTime} and {@code ZoneOffset}.
* The conversion extracts and combines the {@code ZoneOffset} 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 in queries via method reference, {@code OffsetTime::from}.
@ -266,14 +293,14 @@ public final class OffsetTime
* Obtains an instance of {@code OffsetTime} from a text string such as {@code 10:15:30+01:00}.
* <p>
* The string must represent a valid time and is parsed using
* {@link java.time.format.DateTimeFormatters#isoOffsetTime()}.
* {@link java.time.format.DateTimeFormatter#ISO_OFFSET_TIME}.
*
* @param text the text to parse such as "10:15:30+01:00", not null
* @return the parsed local time, not null
* @throws DateTimeParseException if the text cannot be parsed
*/
public static OffsetTime parse(CharSequence text) {
return parse(text, DateTimeFormatters.isoOffsetTime());
return parse(text, DateTimeFormatter.ISO_OFFSET_TIME);
}
/**
@ -347,7 +374,7 @@ public final class OffsetTime
* 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.
*
@ -359,7 +386,7 @@ public final class OffsetTime
if (field instanceof ChronoField) {
return ((ChronoField) field).isTimeField() || field == OFFSET_SECONDS;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
@ -376,7 +403,7 @@ public final class OffsetTime
* 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.
*
@ -392,7 +419,7 @@ public final class OffsetTime
}
return time.range(field);
}
return field.doRange(this);
return field.rangeRefinedBy(this);
}
/**
@ -410,7 +437,7 @@ public final class OffsetTime
* 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.
*
@ -437,7 +464,7 @@ public final class OffsetTime
* 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.
*
@ -450,11 +477,11 @@ public final class OffsetTime
public long getLong(TemporalField field) {
if (field instanceof ChronoField) {
if (field == OFFSET_SECONDS) {
return getOffset().getTotalSeconds();
return offset.getTotalSeconds();
}
return time.getLong(field);
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
@ -526,7 +553,7 @@ public final class OffsetTime
*
* @return the time part of this date-time, not null
*/
public LocalTime getTime() {
public LocalTime toLocalTime() {
return time;
}
@ -571,7 +598,7 @@ public final class OffsetTime
/**
* Returns an adjusted copy of this time.
* <p>
* This returns a new {@code OffsetTime}, based on this one, with the time adjusted.
* This returns an {@code OffsetTime}, based on this one, with the time adjusted.
* The adjustment takes place using the specified adjuster strategy object.
* Read the documentation of the adjuster to understand what adjustment will be made.
* <p>
@ -612,7 +639,7 @@ public final class OffsetTime
/**
* Returns a copy of this time with the specified field set to a new value.
* <p>
* This returns a new {@code OffsetTime}, based on this one, with the value
* This returns an {@code OffsetTime}, based on this one, with the value
* for the specified field changed.
* This can be used to change any supported field, such as the hour, minute or second.
* If it is not possible to set the value, because the field is not supported or for
@ -631,7 +658,7 @@ public final class OffsetTime
* 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>
@ -652,7 +679,7 @@ public final class OffsetTime
}
return with(time.with(field, newValue), offset);
}
return field.doWith(this, newValue);
return field.adjustInto(this, newValue);
}
//-----------------------------------------------------------------------
@ -725,8 +752,10 @@ public final class OffsetTime
* 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>
* The offset does not affect the calculation and will be the same in the result.
* <p>
@ -742,49 +771,60 @@ public final class OffsetTime
//-----------------------------------------------------------------------
/**
* 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 java.time.Period} but may be any other type implementing
* the {@link TemporalAdder} interface.
* The calculation is delegated to the specified adjuster, which typically calls
* back to {@link #plus(long, TemporalUnit)}.
* The offset is not part of the calculation and will be unchanged in the result.
* This returns an {@code OffsetTime}, 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 an {@code OffsetTime} based on this time with the addition made, not null
* @throws DateTimeException if the addition cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public OffsetTime plus(TemporalAdder adder) {
return (OffsetTime) adder.addTo(this);
public OffsetTime plus(TemporalAmount amountToAdd) {
return (OffsetTime) 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 an {@code OffsetTime}, 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 LocalTime#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 period to add, not null
* @return an {@code OffsetTime} based on this time with the specified period added, not null
* @throws DateTimeException if the unit cannot be added to this type
* @param unit the unit of the amount to add, not null
* @return an {@code OffsetTime} 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 OffsetTime plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return with(time.plus(amountToAdd, unit), offset);
}
return unit.doPlus(this, amountToAdd);
return unit.addTo(this, amountToAdd);
}
//-----------------------------------------------------------------------
@ -850,42 +890,47 @@ public final class OffsetTime
//-----------------------------------------------------------------------
/**
* 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 java.time.Period} but may be any other type implementing
* the {@link TemporalSubtractor} interface.
* The calculation is delegated to the specified adjuster, which typically calls
* back to {@link #minus(long, TemporalUnit)}.
* The offset is not part of the calculation and will be unchanged in the result.
* This returns an {@code OffsetTime}, 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 an {@code OffsetTime} based on this time with the subtraction made, not null
* @throws DateTimeException if the subtraction cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public OffsetTime minus(TemporalSubtractor subtractor) {
return (OffsetTime) subtractor.subtractFrom(this);
public OffsetTime minus(TemporalAmount amountToSubtract) {
return (OffsetTime) 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.
* The offset is not part of the calculation and will be unchanged in the result.
* This returns an {@code OffsetTime}, 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 an {@code OffsetTime} based on this time with the specified period subtracted, not null
* @throws DateTimeException if the unit cannot be added to this type
* @param unit the unit of the amount to subtract, not null
* @return an {@code OffsetTime} 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 OffsetTime minus(long amountToSubtract, TemporalUnit unit) {
@ -975,12 +1020,18 @@ public final class OffsetTime
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.precision()) {
if (query == Queries.offset() || query == Queries.zone()) {
return (R) offset;
} else if (query == Queries.zoneId() | query == Queries.chronology() || query == Queries.localDate()) {
return null;
} else if (query == Queries.localTime()) {
return (R) time;
} else if (query == Queries.precision()) {
return (R) NANOS;
} else if (query == Queries.offset() || query == Queries.zone()) {
return (R) getOffset();
}
return Temporal.super.query(query);
// inline TemporalAccessor.super.query(query) as an optimization
// non-JDK classes are not permitted to make this optimization
return query.queryFrom(this);
}
/**
@ -1012,7 +1063,7 @@ public final class OffsetTime
@Override
public Temporal adjustInto(Temporal temporal) {
return temporal
.with(OFFSET_SECONDS, getOffset().getTotalSeconds())
.with(OFFSET_SECONDS, offset.getTotalSeconds())
.with(NANO_OF_DAY, time.toNanoOfDay());
}
@ -1035,14 +1086,15 @@ public final class OffsetTime
* For example, the period in hours between 11:30Z and 13:29Z will only
* be one hour as it is one minute short of two hours.
* <p>
* This method operates in association with {@link TemporalUnit#between}.
* The result of this method is a {@code long} representing the amount of
* the specified unit. By contrast, the result of {@code between} is an
* object that can be used directly in addition/subtraction:
* 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},
@ -1082,17 +1134,15 @@ public final class OffsetTime
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
return unit.between(this, endTime).getAmount();
return unit.between(this, endTime);
}
//-----------------------------------------------------------------------
/**
* Returns an offset date-time formed from this time at the specified date.
* Combines this date with a time to create an {@code OffsetDateTime}.
* <p>
* This combines this time with the specified date to form an {@code OffsetDateTime}.
* This returns an {@code OffsetDateTime} formed from this time and 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 offset date-time formed from this time and the specified date, not null
@ -1261,7 +1311,7 @@ public final class OffsetTime
* 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
@ -1269,7 +1319,7 @@ public final class OffsetTime
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.print(this);
return formatter.format(this);
}
// -----------------------------------------------------------------------
@ -1277,7 +1327,7 @@ public final class OffsetTime
* Writes the object using a
* <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
* <pre>
* out.writeByte(2); // identifies this as a OffsetDateTime
* out.writeByte(9); // identifies this as a OffsetDateTime
* out.writeObject(time);
* out.writeObject(offset);
* </pre>

File diff suppressed because it is too large Load Diff

View File

@ -1,307 +0,0 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of JSR-310 nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time;
import java.time.format.DateTimeParseException;
/**
* A period parser that creates an instance of {@code Period} from a string.
* This parses the ISO-8601 period format {@code PnYnMnDTnHnMn.nS}.
* <p>
* This class is mutable and intended for use by a single thread.
*
* @since 1.8
*/
final class PeriodParser {
/**
* Used to validate the correct sequence of tokens.
*/
private static final String TOKEN_SEQUENCE = "PYMDTHMS";
/**
* The standard string representing a zero period.
*/
private static final String ZERO = "PT0S";
/**
* The number of years.
*/
private int years;
/**
* The number of months.
*/
private int months;
/**
* The number of days.
*/
private int days;
/**
* The number of hours.
*/
private int hours;
/**
* The number of minutes.
*/
private int minutes;
/**
* The number of seconds.
*/
private int seconds;
/**
* The number of nanoseconds.
*/
private long nanos;
/**
* Whether the seconds were negative.
*/
private boolean negativeSecs;
/**
* Parser position index.
*/
private int index;
/**
* Original text.
*/
private CharSequence text;
/**
* Constructor.
*
* @param text the text to parse, not null
*/
PeriodParser(CharSequence text) {
this.text = text;
}
//-----------------------------------------------------------------------
/**
* Performs the parse.
* <p>
* This parses the text set in the constructor in the format PnYnMnDTnHnMn.nS.
*
* @return the created Period, not null
* @throws DateTimeParseException if the text cannot be parsed to a Period
*/
Period parse() {
// force to upper case and coerce the comma to dot
String s = text.toString().toUpperCase().replace(',', '.');
// check for zero and skip parse
if (ZERO.equals(s)) {
return Period.ZERO;
}
if (s.length() < 3 || s.charAt(0) != 'P') {
throw new DateTimeParseException("Period could not be parsed: " + text, text, 0);
}
validateCharactersAndOrdering(s, text);
// strip off the leading P
String[] datetime = s.substring(1).split("T");
switch (datetime.length) {
case 2:
parseDate(datetime[0], 1);
parseTime(datetime[1], datetime[0].length() + 2);
break;
case 1:
parseDate(datetime[0], 1);
break;
}
return toPeriod();
}
private void parseDate(String s, int baseIndex) {
index = 0;
while (index < s.length()) {
String value = parseNumber(s);
if (index < s.length()) {
char c = s.charAt(index);
switch(c) {
case 'Y': years = parseInt(value, baseIndex) ; break;
case 'M': months = parseInt(value, baseIndex) ; break;
case 'D': days = parseInt(value, baseIndex) ; break;
default:
throw new DateTimeParseException("Period could not be parsed, unrecognized letter '" +
c + ": " + text, text, baseIndex + index);
}
index++;
}
}
}
private void parseTime(String s, int baseIndex) {
index = 0;
s = prepareTime(s, baseIndex);
while (index < s.length()) {
String value = parseNumber(s);
if (index < s.length()) {
char c = s.charAt(index);
switch(c) {
case 'H': hours = parseInt(value, baseIndex) ; break;
case 'M': minutes = parseInt(value, baseIndex) ; break;
case 'S': seconds = parseInt(value, baseIndex) ; break;
case 'N': nanos = parseNanos(value, baseIndex); break;
default:
throw new DateTimeParseException("Period could not be parsed, unrecognized letter '" +
c + "': " + text, text, baseIndex + index);
}
index++;
}
}
}
private long parseNanos(String s, int baseIndex) {
if (s.length() > 9) {
throw new DateTimeParseException("Period could not be parsed, nanosecond range exceeded: " +
text, text, baseIndex + index - s.length());
}
// pad to the right to create 10**9, then trim
return Long.parseLong((s + "000000000").substring(0, 9));
}
private String prepareTime(String s, int baseIndex) {
if (s.contains(".")) {
int i = s.indexOf(".") + 1;
// verify that the first character after the dot is a digit
if (Character.isDigit(s.charAt(i))) {
i++;
} else {
throw new DateTimeParseException("Period could not be parsed, invalid decimal number: " +
text, text, baseIndex + index);
}
// verify that only digits follow the decimal point followed by an S
while (i < s.length()) {
// || !Character.isDigit(s.charAt(i))
char c = s.charAt(i);
if (Character.isDigit(c) || c == 'S') {
i++;
} else {
throw new DateTimeParseException("Period could not be parsed, invalid decimal number: " +
text, text, baseIndex + index);
}
}
s = s.replace('S', 'N').replace('.', 'S');
if (s.contains("-0S")) {
negativeSecs = true;
s = s.replace("-0S", "0S");
}
}
return s;
}
private int parseInt(String s, int baseIndex) {
try {
int value = Integer.parseInt(s);
if (s.charAt(0) == '-' && value == 0) {
throw new DateTimeParseException("Period could not be parsed, invalid number '" +
s + "': " + text, text, baseIndex + index - s.length());
}
return value;
} catch (NumberFormatException ex) {
throw new DateTimeParseException("Period could not be parsed, invalid number '" +
s + "': " + text, text, baseIndex + index - s.length());
}
}
private String parseNumber(String s) {
int start = index;
while (index < s.length()) {
char c = s.charAt(index);
if ((c < '0' || c > '9') && c != '-') {
break;
}
index++;
}
return s.substring(start, index);
}
private void validateCharactersAndOrdering(String s, CharSequence text) {
char[] chars = s.toCharArray();
int tokenPos = 0;
boolean lastLetter = false;
for (int i = 0; i < chars.length; i++) {
if (tokenPos >= TOKEN_SEQUENCE.length()) {
throw new DateTimeParseException("Period could not be parsed, characters after last 'S': " + text, text, i);
}
char c = chars[i];
if ((c < '0' || c > '9') && c != '-' && c != '.') {
tokenPos = TOKEN_SEQUENCE.indexOf(c, tokenPos);
if (tokenPos < 0) {
throw new DateTimeParseException("Period could not be parsed, invalid character '" + c + "': " + text, text, i);
}
tokenPos++;
lastLetter = true;
} else {
lastLetter = false;
}
}
if (lastLetter == false) {
throw new DateTimeParseException("Period could not be parsed, invalid last character: " + text, text, s.length() - 1);
}
}
private Period toPeriod() {
return Period.of(years, months, days, hours, minutes, seconds, negativeSecs || seconds < 0 ? -nanos : nanos);
}
}

View File

@ -56,8 +56,6 @@
*/
package java.time;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.Externalizable;
import java.io.IOException;
import java.io.InvalidClassException;
@ -103,6 +101,12 @@ final class Ser implements Externalizable {
static final byte ZONE_DATE_TIME_TYPE = 6;
static final byte ZONE_REGION_TYPE = 7;
static final byte ZONE_OFFSET_TYPE = 8;
static final byte OFFSET_TIME_TYPE = 9;
static final byte OFFSET_DATE_TIME_TYPE = 10;
static final byte YEAR_TYPE = 11;
static final byte YEAR_MONTH_TYPE = 12;
static final byte MONTH_DAY_TYPE = 13;
static final byte PERIOD_TYPE = 14;
/** The type being serialized. */
private byte type;
@ -132,11 +136,12 @@ final class Ser implements Externalizable {
*
* @param out the data stream to write to, not null
*/
@Override
public void writeExternal(ObjectOutput out) throws IOException {
writeInternal(type, object, out);
}
static void writeInternal(byte type, Object object, DataOutput out) throws IOException {
static void writeInternal(byte type, Object object, ObjectOutput out) throws IOException {
out.writeByte(type);
switch (type) {
case DURATION_TYPE:
@ -163,6 +168,24 @@ final class Ser implements Externalizable {
case ZONE_DATE_TIME_TYPE:
((ZonedDateTime) object).writeExternal(out);
break;
case OFFSET_TIME_TYPE:
((OffsetTime) object).writeExternal(out);
break;
case OFFSET_DATE_TIME_TYPE:
((OffsetDateTime) object).writeExternal(out);
break;
case YEAR_TYPE:
((Year) object).writeExternal(out);
break;
case YEAR_MONTH_TYPE:
((YearMonth) object).writeExternal(out);
break;
case MONTH_DAY_TYPE:
((MonthDay) object).writeExternal(out);
break;
case PERIOD_TYPE:
((Period) object).writeExternal(out);
break;
default:
throw new InvalidClassException("Unknown serialized type");
}
@ -174,17 +197,17 @@ final class Ser implements Externalizable {
*
* @param in the data to read, not null
*/
public void readExternal(ObjectInput in) throws IOException {
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
type = in.readByte();
object = readInternal(type, in);
}
static Object read(DataInput in) throws IOException {
static Object read(ObjectInput in) throws IOException, ClassNotFoundException {
byte type = in.readByte();
return readInternal(type, in);
}
private static Object readInternal(byte type, DataInput in) throws IOException {
private static Object readInternal(byte type, ObjectInput in) throws IOException, ClassNotFoundException {
switch (type) {
case DURATION_TYPE: return Duration.readExternal(in);
case INSTANT_TYPE: return Instant.readExternal(in);
@ -194,6 +217,12 @@ final class Ser implements Externalizable {
case ZONE_DATE_TIME_TYPE: return ZonedDateTime.readExternal(in);
case ZONE_OFFSET_TYPE: return ZoneOffset.readExternal(in);
case ZONE_REGION_TYPE: return ZoneRegion.readExternal(in);
case OFFSET_TIME_TYPE: return OffsetTime.readExternal(in);
case OFFSET_DATE_TIME_TYPE: return OffsetDateTime.readExternal(in);
case YEAR_TYPE: return Year.readExternal(in);
case YEAR_MONTH_TYPE: return YearMonth.readExternal(in);
case MONTH_DAY_TYPE: return MonthDay.readExternal(in);
case PERIOD_TYPE: return Period.readExternal(in);
default:
throw new StreamCorruptedException("Unknown serialized type");
}

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoField.YEAR;
@ -72,15 +72,23 @@ import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.time.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.format.SignStyle;
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.util.Objects;
/**
@ -211,8 +219,9 @@ public final class Year
/**
* Obtains an instance of {@code Year} from a temporal object.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code Year}.
* This obtains a year 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 Year}.
* <p>
* The conversion extracts the {@link ChronoField#YEAR year} field.
* The extraction is only permitted if the temporal object has an ISO
@ -230,7 +239,7 @@ public final class Year
return (Year) 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(YEAR));
@ -324,8 +333,6 @@ public final class Year
* {@link #get(TemporalField) get} methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this date-time.
* The supported fields are:
* <ul>
* <li>{@code YEAR_OF_ERA}
@ -335,7 +342,7 @@ public final class Year
* 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.
*
@ -347,7 +354,7 @@ public final class Year
if (field instanceof ChronoField) {
return field == YEAR || field == YEAR_OF_ERA || field == ERA;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
@ -364,7 +371,7 @@ public final class Year
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.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.
*
@ -394,7 +401,7 @@ public final class Year
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
* 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.
*
@ -421,7 +428,7 @@ public final class Year
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
* 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.
*
@ -440,7 +447,7 @@ public final class Year
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
@ -492,7 +499,7 @@ public final class Year
/**
* Returns an adjusted copy of this year.
* <p>
* This returns a new {@code Year}, based on this one, with the year adjusted.
* This returns a {@code Year}, based on this one, with the year adjusted.
* The adjustment takes place using the specified adjuster strategy object.
* Read the documentation of the adjuster to understand what adjustment will be made.
* <p>
@ -515,7 +522,7 @@ public final class Year
/**
* Returns a copy of this year with the specified field set to a new value.
* <p>
* This returns a new {@code Year}, based on this one, with the value
* This returns a {@code Year}, based on this one, with the value
* for the specified field changed.
* If it is not possible to set the value, because the field is not supported or for
* some other reason, an exception is thrown.
@ -540,7 +547,7 @@ public final class Year
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.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>
@ -564,35 +571,81 @@ public final class Year
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doWith(this, newValue);
return field.adjustInto(this, newValue);
}
//-----------------------------------------------------------------------
/**
* Returns a copy of this year with the specified period added.
* Returns a copy of this year with the specified amount added.
* <p>
* This method returns a new year based on this year with the specified period added.
* The adder is typically {@link java.time.Period} but may be any other type implementing
* the {@link TemporalAdder} interface.
* The calculation is delegated to the specified adjuster, which typically calls
* back to {@link #plus(long, TemporalUnit)}.
* This returns a {@code Year}, 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 Year} based on this year with the addition made, not null
* @throws DateTimeException if the addition cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public Year plus(TemporalAdder adder) {
return (Year) adder.addTo(this);
public Year plus(TemporalAmount amountToAdd) {
return (Year) amountToAdd.addTo(this);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
* Returns a copy of this year with the specified amount added.
* <p>
* This returns a {@code Year}, 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 YEARS} -
* Returns a {@code Year} with the specified number of years added.
* This is equivalent to {@link #plusYears(long)}.
* <li>{@code DECADES} -
* Returns a {@code Year} with the specified number of decades added.
* This is equivalent to calling {@link #plusYears(long)} with the amount
* multiplied by 10.
* <li>{@code CENTURIES} -
* Returns a {@code Year} with the specified number of centuries added.
* This is equivalent to calling {@link #plusYears(long)} with the amount
* multiplied by 100.
* <li>{@code MILLENNIA} -
* Returns a {@code Year} with the specified number of millennia added.
* This is equivalent to calling {@link #plusYears(long)} with the amount
* multiplied by 1,000.
* <li>{@code ERAS} -
* Returns a {@code Year} 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.
* </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 a {@code Year} based on this year with the specified amount added, not null
* @throws DateTimeException if the addition cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public Year plus(long amountToAdd, TemporalUnit unit) {
@ -606,7 +659,7 @@ public final class Year
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
return unit.doPlus(this, amountToAdd);
return unit.addTo(this, amountToAdd);
}
/**
@ -627,30 +680,47 @@ public final class Year
//-----------------------------------------------------------------------
/**
* Returns a copy of this year with the specified period subtracted.
* Returns a copy of this year with the specified amount subtracted.
* <p>
* This method returns a new year based on this year with the specified period subtracted.
* The subtractor is typically {@link java.time.Period} but may be any other type implementing
* the {@link TemporalSubtractor} interface.
* The calculation is delegated to the specified adjuster, which typically calls
* back to {@link #minus(long, TemporalUnit)}.
* This returns a {@code Year}, 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 Year} based on this year with the subtraction made, not null
* @throws DateTimeException if the subtraction cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public Year minus(TemporalSubtractor subtractor) {
return (Year) subtractor.subtractFrom(this);
public Year minus(TemporalAmount amountToSubtract) {
return (Year) amountToSubtract.subtractFrom(this);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
* Returns a copy of this year-month with the specified amount subtracted.
* <p>
* This returns a {@code YearMonth}, 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 a {@code YearMonth} based on this year-month with the specified amount subtracted, not null
* @throws DateTimeException if the subtraction cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public Year minus(long amountToSubtract, TemporalUnit unit) {
@ -692,8 +762,8 @@ public final class Year
@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) YEARS;
}
@ -728,7 +798,7 @@ public final class Year
*/
@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(YEAR, year);
@ -750,14 +820,15 @@ public final class Year
* For example, the period in decades between 2012 and 2031
* will only be one decade as it is one year short of two decades.
* <p>
* This method operates in association with {@link TemporalUnit#between}.
* The result of this method is a {@code long} representing the amount of
* the specified unit. By contrast, the result of {@code between} is an
* object that can be used directly in addition/subtraction:
* 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, YEARS); // this method
* dateTime.plus(YEARS.between(start, end)); // use in plus/minus
* // these two lines are equivalent
* amount = start.periodUntil(end, YEARS);
* amount = YEARS.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 YEARS}, {@code DECADES}, {@code CENTURIES},
@ -795,38 +866,36 @@ public final class Year
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
return unit.between(this, endYear).getAmount();
return unit.between(this, endYear);
}
//-----------------------------------------------------------------------
/**
* Returns a date formed from this year at the specified day-of-year.
* Combines this year with a day-of-year to create a {@code LocalDate}.
* <p>
* This returns a {@code LocalDate} formed from this year and the specified day-of-year.
* <p>
* This combines this year and the specified day-of-year to form a {@code LocalDate}.
* The day-of-year value 366 is only valid in a leap year.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param dayOfYear the day-of-year to use, not null
* @return the local date formed from this year and the specified date of year, not null
* @throws DateTimeException if the day of year is 366 and this is not a leap year
* @throws DateTimeException if the day of year is zero or less, 366 or greater or equal
* to 366 and this is not a leap year
*/
public LocalDate atDay(int dayOfYear) {
return LocalDate.ofYearDay(year, dayOfYear);
}
/**
* Returns a year-month formed from this year at the specified month.
* Combines this year with a month to create a {@code YearMonth}.
* <p>
* This combines this year and the specified month to form a {@code YearMonth}.
* This returns a {@code YearMonth} formed from this year and the specified month.
* All possible combinations of year and month are valid.
* <p>
* This method can be used as part of a chain to produce a date:
* <pre>
* LocalDate date = year.atMonth(month).atDay(day);
* </pre>
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param month the month-of-year to use, not null
* @return the year-month formed from this year and the specified month, not null
@ -836,39 +905,37 @@ public final class Year
}
/**
* Returns a year-month formed from this year at the specified month.
* Combines this year with a month to create a {@code YearMonth}.
* <p>
* This combines this year and the specified month to form a {@code YearMonth}.
* This returns a {@code YearMonth} formed from this year and the specified month.
* All possible combinations of year and month are valid.
* <p>
* This method can be used as part of a chain to produce a date:
* <pre>
* LocalDate date = year.atMonth(month).atDay(day);
* </pre>
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param month the month-of-year to use, from 1 (January) to 12 (December)
* @return the year-month formed from this year and the specified month, not null
* @throws DateTimeException if the month is invalid
*/
public YearMonth atMonth(int month) {
return YearMonth.of(year, month);
}
/**
* Returns a date formed from this year at the specified month-day.
* Combines this year with a month-day to create a {@code LocalDate}.
* <p>
* This combines this year and the specified month-day to form a {@code LocalDate}.
* The month-day value of February 29th is only valid in a leap year.
* This returns a {@code LocalDate} formed from this year and the specified month-day.
* <p>
* This instance is immutable and unaffected by this method call.
* A month-day of February 29th will be adjusted to February 28th in the resulting
* date if the year is not a leap year.
*
* @param monthDay the month-day to use, not null
* @return the local date formed from this year and the specified month-day, not null
* @throws DateTimeException if the month-day is February 29th and this is not a leap year
*/
public LocalDate atMonthDay(MonthDay monthDay) {
return LocalDate.of(year, monthDay.getMonth(), monthDay.getDayOfMonth());
return monthDay.atYear(year);
}
//-----------------------------------------------------------------------
@ -881,6 +948,7 @@ public final class Year
* @param other the other year to compare to, not null
* @return the comparator value, negative if less, positive if greater
*/
@Override
public int compareTo(Year other) {
return year - other.year;
}
@ -950,7 +1018,7 @@ public final class Year
* Outputs this year as a {@code String} using the formatter.
* <p>
* This year will be passed to the formatter
* {@link DateTimeFormatter#print(TemporalAccessor) print method}.
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted year string, not null
@ -958,7 +1026,7 @@ public final class Year
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.print(this);
return formatter.format(this);
}
//-----------------------------------------------------------------------
@ -966,7 +1034,7 @@ public final class Year
* Writes the object using a
* <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
* <pre>
* out.writeByte(4); // identifies this as a Year
* out.writeByte(11); // identifies this as a Year
* out.writeInt(year);
* </pre>
*

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time;
import static java.time.temporal.ChronoField.EPOCH_MONTH;
import static java.time.temporal.ChronoField.ERA;
@ -74,15 +74,23 @@ import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.time.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.format.SignStyle;
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.util.Objects;
/**
@ -212,8 +220,9 @@ public final class YearMonth
/**
* Obtains an instance of {@code YearMonth} from a temporal object.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code YearMonth}.
* This obtains a year-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 YearMonth}.
* <p>
* The conversion extracts the {@link ChronoField#YEAR YEAR} and
* {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} fields.
@ -232,7 +241,7 @@ public final class YearMonth
return (YearMonth) 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(YEAR), temporal.get(MONTH_OF_YEAR));
@ -308,8 +317,6 @@ public final class YearMonth
* {@link #get(TemporalField) get} methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this date-time.
* The supported fields are:
* <ul>
* <li>{@code MONTH_OF_YEAR}
@ -321,7 +328,7 @@ public final class YearMonth
* 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.
*
@ -334,7 +341,7 @@ public final class YearMonth
return field == YEAR || field == MONTH_OF_YEAR ||
field == EPOCH_MONTH || field == YEAR_OF_ERA || field == ERA;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
@ -351,7 +358,7 @@ public final class YearMonth
* 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.
*
@ -382,7 +389,7 @@ public final class YearMonth
* 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.
*
@ -409,7 +416,7 @@ public final class YearMonth
* 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.
*
@ -430,7 +437,7 @@ public final class YearMonth
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
private long getEpochMonth() {
@ -451,6 +458,20 @@ public final class YearMonth
return year;
}
/**
* Gets the month-of-year field from 1 to 12.
* <p>
* This method returns the month as an {@code int} from 1 to 12.
* Application code is frequently clearer if the enum {@link Month}
* is used by calling {@link #getMonth()}.
*
* @return the month-of-year, from 1 to 12
* @see #getMonth()
*/
public int getMonthValue() {
return month;
}
/**
* Gets the month-of-year field using the {@code Month} enum.
* <p>
@ -460,6 +481,7 @@ public final class YearMonth
* provides the {@link Month#getValue() int value}.
*
* @return the month-of-year, not null
* @see #getMonthValue()
*/
public Month getMonth() {
return Month.of(month);
@ -485,7 +507,7 @@ public final class YearMonth
* @return true if the year is leap, false otherwise
*/
public boolean isLeapYear() {
return ISOChrono.INSTANCE.isLeapYear(year);
return IsoChronology.INSTANCE.isLeapYear(year);
}
/**
@ -528,7 +550,7 @@ public final class YearMonth
/**
* Returns an adjusted copy of this year-month.
* <p>
* This returns a new {@code YearMonth}, based on this one, with the year-month adjusted.
* This returns a {@code YearMonth}, based on this one, with the year-month adjusted.
* The adjustment takes place using the specified adjuster strategy object.
* Read the documentation of the adjuster to understand what adjustment will be made.
* <p>
@ -555,7 +577,7 @@ public final class YearMonth
/**
* Returns a copy of this year-month with the specified field set to a new value.
* <p>
* This returns a new {@code YearMonth}, based on this one, with the value
* This returns a {@code YearMonth}, based on this one, with the value
* for the specified field changed.
* This can be used to change any supported field, such as the year or month.
* If it is not possible to set the value, because the field is not supported or for
@ -587,7 +609,7 @@ public final class YearMonth
* 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>
@ -613,7 +635,7 @@ public final class YearMonth
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doWith(this, newValue);
return field.adjustInto(this, newValue);
}
//-----------------------------------------------------------------------
@ -647,30 +669,79 @@ public final class YearMonth
//-----------------------------------------------------------------------
/**
* Returns a copy of this year-month with the specified period added.
* Returns a copy of this year-month with the specified amount added.
* <p>
* This method returns a new year-month based on this year-month with the specified period added.
* The adder is typically {@link java.time.Period} but may be any other type implementing
* the {@link TemporalAdder} interface.
* The calculation is delegated to the specified adjuster, which typically calls
* back to {@link #plus(long, TemporalUnit)}.
* This returns a {@code YearMonth}, 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 YearMonth} based on this year-month with the addition made, not null
* @throws DateTimeException if the addition cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public YearMonth plus(TemporalAdder adder) {
return (YearMonth) adder.addTo(this);
public YearMonth plus(TemporalAmount amountToAdd) {
return (YearMonth) amountToAdd.addTo(this);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
* Returns a copy of this year-month with the specified amount added.
* <p>
* This returns a {@code YearMonth}, 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 MONTHS} -
* Returns a {@code YearMonth} with the specified number of months added.
* This is equivalent to {@link #plusMonths(long)}.
* <li>{@code YEARS} -
* Returns a {@code YearMonth} with the specified number of years added.
* This is equivalent to {@link #plusYears(long)}.
* <li>{@code DECADES} -
* Returns a {@code YearMonth} with the specified number of decades added.
* This is equivalent to calling {@link #plusYears(long)} with the amount
* multiplied by 10.
* <li>{@code CENTURIES} -
* Returns a {@code YearMonth} with the specified number of centuries added.
* This is equivalent to calling {@link #plusYears(long)} with the amount
* multiplied by 100.
* <li>{@code MILLENNIA} -
* Returns a {@code YearMonth} with the specified number of millennia added.
* This is equivalent to calling {@link #plusYears(long)} with the amount
* multiplied by 1,000.
* <li>{@code ERAS} -
* Returns a {@code YearMonth} 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.
* </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 a {@code YearMonth} based on this year-month with the specified amount added, not null
* @throws DateTimeException if the addition cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public YearMonth plus(long amountToAdd, TemporalUnit unit) {
@ -685,7 +756,7 @@ public final class YearMonth
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
return unit.doPlus(this, amountToAdd);
return unit.addTo(this, amountToAdd);
}
/**
@ -727,30 +798,47 @@ public final class YearMonth
//-----------------------------------------------------------------------
/**
* Returns a copy of this year-month with the specified period subtracted.
* Returns a copy of this year-month with the specified amount subtracted.
* <p>
* This method returns a new year-month based on this year-month with the specified period subtracted.
* The subtractor is typically {@link java.time.Period} but may be any other type implementing
* the {@link TemporalSubtractor} interface.
* The calculation is delegated to the specified adjuster, which typically calls
* back to {@link #minus(long, TemporalUnit)}.
* This returns a {@code YearMonth}, 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 YearMonth} based on this year-month with the subtraction made, not null
* @throws DateTimeException if the subtraction cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public YearMonth minus(TemporalSubtractor subtractor) {
return (YearMonth) subtractor.subtractFrom(this);
public YearMonth minus(TemporalAmount amountToSubtract) {
return (YearMonth) amountToSubtract.subtractFrom(this);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
* Returns a copy of this year-month with the specified amount subtracted.
* <p>
* This returns a {@code YearMonth}, 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 a {@code YearMonth} based on this year-month with the specified amount subtracted, not null
* @throws DateTimeException if the subtraction cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public YearMonth minus(long amountToSubtract, TemporalUnit unit) {
@ -805,8 +893,8 @@ public final class YearMonth
@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;
}
@ -841,7 +929,7 @@ public final class YearMonth
*/
@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(EPOCH_MONTH, getEpochMonth());
@ -863,14 +951,15 @@ public final class YearMonth
* For example, the period in decades between 2012-06 and 2032-05
* will only be one decade as it is one month short of two decades.
* <p>
* This method operates in association with {@link TemporalUnit#between}.
* The result of this method is a {@code long} representing the amount of
* the specified unit. By contrast, the result of {@code between} is an
* object that can be used directly in addition/subtraction:
* 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, YEARS); // this method
* dateTime.plus(YEARS.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 MONTHS}, {@code YEARS}, {@code DECADES},
@ -909,32 +998,49 @@ public final class YearMonth
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
return unit.between(this, endYearMonth).getAmount();
return unit.between(this, endYearMonth);
}
//-----------------------------------------------------------------------
/**
* Returns a date formed from this year-month at the specified day-of-month.
* Combines this year-month with a day-of-month to create a {@code LocalDate}.
* <p>
* This returns a {@code LocalDate} formed from this year-month and the specified day-of-month.
* <p>
* This combines this year-month and the specified day-of-month to form a {@code LocalDate}.
* The day-of-month value must be valid for the year-month.
* <p>
* This method can be used as part of a chain to produce a date:
* <pre>
* LocalDate date = year.atMonth(month).atDay(day);
* </pre>
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param dayOfMonth the day-of-month to use, from 1 to 31
* @return the date formed from this year-month and the specified day, not null
* @throws DateTimeException when the day is invalid for the year-month
* @throws DateTimeException if the day is invalid for the year-month
* @see #isValidDay(int)
*/
public LocalDate atDay(int dayOfMonth) {
return LocalDate.of(year, month, dayOfMonth);
}
/**
* Returns a {@code LocalDate} at the end of the month.
* <p>
* This returns a {@code LocalDate} based on this year-month.
* The day-of-month is set to the last valid day of the month, taking
* into account leap years.
* <p>
* This method can be used as part of a chain to produce a date:
* <pre>
* LocalDate date = year.atMonth(month).atEndOfMonth();
* </pre>
*
* @return the last valid date of this year-month, not null
*/
public LocalDate atEndOfMonth() {
return LocalDate.of(year, month, lengthOfMonth());
}
//-----------------------------------------------------------------------
/**
* Compares this year-month to another year-month.
@ -1035,7 +1141,7 @@ public final class YearMonth
* Outputs this year-month as a {@code String} using the formatter.
* <p>
* This year-month will be passed to the formatter
* {@link DateTimeFormatter#print(TemporalAccessor) print method}.
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted year-month string, not null
@ -1043,7 +1149,7 @@ public final class YearMonth
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.print(this);
return formatter.format(this);
}
//-----------------------------------------------------------------------
@ -1051,7 +1157,7 @@ public final class YearMonth
* Writes the object using a
* <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
* <pre>
* out.writeByte(5); // identifies this as a Year
* out.writeByte(12); // identifies this as a YearMonth
* out.writeInt(year);
* out.writeByte(month);
* </pre>

View File

@ -71,6 +71,7 @@ import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.zone.ZoneRules;
import java.time.zone.ZoneRulesException;
import java.time.zone.ZoneRulesProvider;
import java.util.Collections;
import java.util.HashMap;
@ -111,10 +112,11 @@ import java.util.TimeZone;
* The ID is unique within the system.
* The formats for offset and region IDs differ.
* <p>
* An ID is parsed as an offset ID if it starts with 'UTC', 'GMT', '+' or '-', or
* is a single letter.
* For example, 'Z', '+02:00', '-05:00', 'UTC+05' and 'GMT-6' are all valid offset IDs.
* Note that some IDs, such as 'D' or '+ABC' meet the criteria, but are invalid.
* An ID is parsed as an offset ID if it starts with 'UTC', 'GMT', 'UT' '+' or '-', or
* is a single letter. For example, 'Z', '+02:00', '-05:00', 'UTC+05', 'GMT-6' and
* 'UT+01:00' are all valid offset IDs.
* Note that some IDs, such as 'D' or '+ABC' meet the criteria to be parsed as offset IDs,
* but have an invalid offset.
* <p>
* All other IDs are considered to be region IDs.
* <p>
@ -126,11 +128,11 @@ import java.util.TimeZone;
* The default group is the IANA Time Zone Database (TZDB).
* Other organizations include IATA (the airline industry body) and Microsoft.
* <p>
* Each group defines its own format for region ID.
* Each group defines its own format for the region ID it provides.
* The TZDB group defines IDs such as 'Europe/London' or 'America/New_York'.
* TZDB IDs take precedence over other groups.
* <p>
* It is strongly recommended that the group name is included in all Ids supplied by
* It is strongly recommended that the group name is included in all IDs supplied by
* groups other than TZDB to avoid conflicts. For example, IATA airline time-zone
* region IDs are typically the same as the three letter airport code.
* However, the airport of Utrecht has the code 'UTC', which is obviously a conflict.
@ -140,7 +142,7 @@ import java.util.TimeZone;
* <h3>Specification for implementors</h3>
* This abstract class has two implementations, both of which are immutable and thread-safe.
* One implementation models region-based IDs, the other is {@code ZoneOffset} modelling
* offset-based IDs.
* offset-based IDs. This difference is visible in serialization.
*
* @since 1.8
*/
@ -151,8 +153,8 @@ public abstract class ZoneId implements Serializable {
* <p>
* This maps as follows:
* <p><ul>
* <li>EST - America/Indianapolis</li>
* <li>MST - America/Phoenix</li>
* <li>EST - America/New_York</li>
* <li>MST - America/Denver</li>
* <li>HST - Pacific/Honolulu</li>
* <li>ACT - Australia/Darwin</li>
* <li>AET - Australia/Sydney</li>
@ -248,8 +250,8 @@ public abstract class ZoneId implements Serializable {
base.put("SST", "Pacific/Guadalcanal");
base.put("VST", "Asia/Ho_Chi_Minh");
Map<String, String> pre = new HashMap<>(base);
pre.put("EST", "America/Indianapolis");
pre.put("MST", "America/Phoenix");
pre.put("EST", "America/New_York");
pre.put("MST", "America/Denver");
pre.put("HST", "Pacific/Honolulu");
OLD_IDS_PRE_2005 = Collections.unmodifiableMap(pre);
Map<String, String> post = new HashMap<>(base);
@ -273,7 +275,7 @@ public abstract class ZoneId implements Serializable {
*
* @return the zone ID, not null
* @throws DateTimeException if the converted zone ID has an invalid format
* @throws java.time.zone.ZoneRulesException if the converted zone region ID cannot be found
* @throws ZoneRulesException if the converted zone region ID cannot be found
*/
public static ZoneId systemDefault() {
return ZoneId.of(TimeZone.getDefault().getID(), OLD_IDS_POST_2005);
@ -294,7 +296,7 @@ public abstract class ZoneId implements Serializable {
* @param aliasMap a map of alias zone IDs (typically abbreviations) to real zone IDs, not null
* @return the zone ID, not null
* @throws DateTimeException if the zone ID has an invalid format
* @throws java.time.zone.ZoneRulesException if the zone region ID cannot be found
* @throws ZoneRulesException if the zone ID is a region ID that cannot be found
*/
public static ZoneId of(String zoneId, Map<String, String> aliasMap) {
Objects.requireNonNull(zoneId, "zoneId");
@ -311,22 +313,22 @@ public abstract class ZoneId implements Serializable {
* This method parses the ID, applies any appropriate normalization, and validates it
* against the known set of IDs for which rules are available.
* <p>
* An ID is parsed as though it is an offset ID if it starts with 'UTC', 'GMT', '+'
* An ID is parsed as though it is an offset ID if it starts with 'UTC', 'GMT', 'UT', '+'
* or '-', or if it has less then two letters.
* The offset of {@link ZoneOffset#UTC zero} may be represented in multiple ways,
* including 'Z', 'UTC', 'GMT', 'UTC0' 'GMT0', '+00:00', '-00:00' and 'UTC+00:00'.
* The offset of {@linkplain ZoneOffset#UTC zero} may be represented in multiple ways,
* including 'Z', 'UTC', 'GMT', 'UT', 'UTC0', 'GMT0', 'UT0', '+00:00', '-00:00' and 'UTC+00:00'.
* <p>
* Eight forms of ID are recognized, where '{offset}' means to parse using {@link ZoneOffset#of(String)}:
* Six forms of ID are recognized:
* <p><ul>
* <li><code>{offset}</code> - a {@link ZoneOffset} ID, such as 'Z' or '+02:00'
* <li><code>UTC</code> - alternate form of a {@code ZoneOffset} ID equal to 'Z'
* <li><code>UTC0</code> - alternate form of a {@code ZoneOffset} ID equal to 'Z'
* <li><code>UTC{offset}</code> - alternate form of a {@code ZoneOffset} ID equal to '{offset}'
* <li><code>GMT</code> - alternate form of a {@code ZoneOffset} ID equal to 'Z'
* <li><code>GMT0</code> - alternate form of a {@code ZoneOffset} ID equal to 'Z'
* <li><code>GMT{offset}</code> - alternate form of a {@code ZoneOffset} ID equal to '{offset}'r
* <li><code>Z</code> - an offset of zero, which is {@code ZoneOffset.UTC}
* <li><code>{offset}</code> - a {@code ZoneOffset} ID, such as '+02:00'
* <li><code>{utcPrefix}</code> - a {@code ZoneOffset} ID equal to 'Z'
* <li><code>{utcPrefix}0</code> - a {@code ZoneOffset} ID equal to 'Z'
* <li><code>{utcPrefix}{offset}</code> - a {@code ZoneOffset} ID equal to '{offset}'
* <li><code>{regionID}</code> - full region ID, loaded from configuration
* </ul><p>
* The {offset} is a valid format for {@link ZoneOffset#of(String)}, excluding 'Z'.
* The {utcPrefix} is 'UTC', 'GMT' or 'UT'.
* Region IDs must match the regular expression <code>[A-Za-z][A-Za-z0-9~/._+-]+</code>.
* <p>
* The detailed format of the region ID depends on the group supplying the data.
@ -337,25 +339,52 @@ public abstract class ZoneId implements Serializable {
* @param zoneId the time-zone ID, not null
* @return the zone ID, not null
* @throws DateTimeException if the zone ID has an invalid format
* @throws java.time.zone.ZoneRulesException if the zone region ID cannot be found
* @throws ZoneRulesException if the zone ID is a region ID that cannot be found
*/
public static ZoneId of(String zoneId) {
Objects.requireNonNull(zoneId, "zoneId");
if (zoneId.length() <= 1 || zoneId.startsWith("+") || zoneId.startsWith("-")) {
return ZoneOffset.of(zoneId);
} else if (zoneId.startsWith("UTC") || zoneId.startsWith("GMT")) {
if (zoneId.length() == 3 || (zoneId.length() == 4 && zoneId.charAt(3) == '0')) {
return ZoneOffset.UTC;
}
return ZoneOffset.of(zoneId.substring(3));
return ofWithPrefix(zoneId, 3);
} else if (zoneId.startsWith("UT")) {
return ofWithPrefix(zoneId, 2);
}
return ZoneRegion.ofId(zoneId, true);
}
/**
* Parse once a prefix is established.
*
* @param zoneId the time-zone ID, not null
* @param prefixLength the length of the prefix, 2 or 3
* @return the zone ID, not null
* @return the zone ID, not null
* @throws DateTimeException if the zone ID has an invalid format
*/
private static ZoneId ofWithPrefix(String zoneId, int prefixLength) {
if (zoneId.length() == prefixLength ||
(zoneId.length() == prefixLength + 1 && zoneId.charAt(prefixLength) == '0')) {
return ZoneOffset.UTC;
}
if (zoneId.charAt(prefixLength) == '+' || zoneId.charAt(prefixLength) == '-') {
try {
return ZoneOffset.of(zoneId.substring(prefixLength));
} catch (DateTimeException ex) {
throw new DateTimeException("Invalid ID for offset-based ZoneId: " + zoneId, ex);
}
}
throw new DateTimeException("Invalid ID for offset-based ZoneId: " + zoneId);
}
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code ZoneId} from a temporal object.
* <p>
* This obtains a zone 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 ZoneId}.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code ZoneId}.
* <p>
@ -417,7 +446,7 @@ public abstract class ZoneId implements Serializable {
* {@link ZoneOffset} will always return a set of rules where the offset never changes.
*
* @return the rules, not null
* @throws DateTimeException if no rules are available for this ID
* @throws ZoneRulesException if no rules are available for this ID
*/
public abstract ZoneRules getRules();
@ -426,7 +455,9 @@ public abstract class ZoneId implements Serializable {
* Gets the textual representation of the zone, such as 'British Time' or
* '+02:00'.
* <p>
* This returns a textual description for the time-zone ID.
* This returns the textual name used to identify the time-zone ID,
* 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 #getId() full ID} is returned.
*
@ -434,8 +465,8 @@ public abstract class ZoneId implements Serializable {
* @param locale the locale to use, not null
* @return the text value of the zone, not null
*/
public String getText(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendZoneText(style).toFormatter(locale).print(new TemporalAccessor() {
public String getDisplayName(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendZoneText(style).toFormatter(locale).format(new TemporalAccessor() {
@Override
public boolean isSupported(TemporalField field) {
return false;

View File

@ -61,6 +61,9 @@
*/
package java.time;
import static java.time.LocalTime.MINUTES_PER_HOUR;
import static java.time.LocalTime.SECONDS_PER_HOUR;
import static java.time.LocalTime.SECONDS_PER_MINUTE;
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
import java.io.DataInput;
@ -125,18 +128,6 @@ public final class ZoneOffset
/** Cache of time-zone offset by ID. */
private static final ConcurrentMap<String, ZoneOffset> ID_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
/**
* The number of seconds per hour.
*/
private static final int SECONDS_PER_HOUR = 60 * 60;
/**
* The number of seconds per minute.
*/
private static final int SECONDS_PER_MINUTE = 60;
/**
* The number of minutes per hour.
*/
private static final int MINUTES_PER_HOUR = 60;
/**
* The abs maximum seconds.
*/
@ -239,11 +230,11 @@ public final class ZoneOffset
seconds = parseNumber(offsetId, 7, true);
break;
default:
throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid");
throw new DateTimeException("Invalid ID for ZoneOffset, invalid format: " + offsetId);
}
char first = offsetId.charAt(0);
if (first != '+' && first != '-') {
throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Plus/minus not found when expected");
throw new DateTimeException("Invalid ID for ZoneOffset, plus/minus not found when expected: " + offsetId);
}
if (first == '-') {
return ofHoursMinutesSeconds(-hours, -minutes, -seconds);
@ -262,12 +253,12 @@ public final class ZoneOffset
*/
private static int parseNumber(CharSequence offsetId, int pos, boolean precededByColon) {
if (precededByColon && offsetId.charAt(pos - 1) != ':') {
throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Colon not found when expected");
throw new DateTimeException("Invalid ID for ZoneOffset, colon not found when expected: " + offsetId);
}
char ch1 = offsetId.charAt(pos);
char ch2 = offsetId.charAt(pos + 1);
if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') {
throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Non numeric characters found");
throw new DateTimeException("Invalid ID for ZoneOffset, non numeric characters found: " + offsetId);
}
return (ch1 - 48) * 10 + (ch2 - 48);
}
@ -324,10 +315,15 @@ public final class ZoneOffset
/**
* Obtains an instance of {@code ZoneOffset} from a temporal object.
* <p>
* This obtains an offset 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 ZoneOffset}.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code ZoneOffset}.
* <p>
* The conversion extracts the {@link ChronoField#OFFSET_SECONDS offset-seconds} field.
* The conversion uses the {@link Queries#offset()} query, which relies
* on extracting the {@link ChronoField#OFFSET_SECONDS OFFSET_SECONDS} field.
* <p>
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used in queries via method reference, {@code ZoneOffset::from}.
@ -337,14 +333,11 @@ public final class ZoneOffset
* @throws DateTimeException if unable to convert to an {@code ZoneOffset}
*/
public static ZoneOffset from(TemporalAccessor temporal) {
if (temporal instanceof ZoneOffset) {
return (ZoneOffset) temporal;
}
try {
return ofTotalSeconds(temporal.get(OFFSET_SECONDS));
} catch (DateTimeException ex) {
throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " + temporal.getClass(), ex);
ZoneOffset offset = temporal.query(Queries.offset());
if (offset == null) {
throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " + temporal.getClass());
}
return offset;
}
//-----------------------------------------------------------------------
@ -515,7 +508,7 @@ public final class ZoneOffset
* 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.
*
@ -527,7 +520,7 @@ public final class ZoneOffset
if (field instanceof ChronoField) {
return field == OFFSET_SECONDS;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
@ -544,7 +537,7 @@ public final class ZoneOffset
* 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.
*
@ -570,7 +563,7 @@ public final class ZoneOffset
* 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.
*
@ -601,7 +594,7 @@ public final class ZoneOffset
* 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.
*
@ -617,7 +610,7 @@ public final class ZoneOffset
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------

View File

@ -113,7 +113,7 @@ final class ZoneRegion extends ZoneId implements Serializable {
* if the time-zone has available rules.
* <p>
* This method parses the ID and applies any appropriate normalization.
* It does not validate the ID against the known set of IDsfor which rules are available.
* It does not validate the ID against the known set of IDs for which rules are available.
* <p>
* This method is intended for advanced use cases.
* For example, consider a system that always retrieves time-zone rules from a remote server.
@ -135,18 +135,20 @@ final class ZoneRegion extends ZoneId implements Serializable {
* @param checkAvailable whether to check if the zone ID is available
* @return the zone ID, not null
* @throws DateTimeException if the ID format is invalid
* @throws DateTimeException if checking availability and the ID cannot be found
* @throws ZoneRulesException if checking availability and the ID cannot be found
*/
static ZoneRegion ofId(String zoneId, boolean checkAvailable) {
Objects.requireNonNull(zoneId, "zoneId");
if (zoneId.length() < 2 || zoneId.startsWith("UTC") ||
zoneId.startsWith("GMT") || (PATTERN.matcher(zoneId).matches() == false)) {
throw new DateTimeException("ZoneId format is not a valid region format");
if (zoneId.length() < 2 ||
zoneId.startsWith("UT") || // includes UTC
zoneId.startsWith("GMT") ||
(PATTERN.matcher(zoneId).matches() == false)) {
throw new DateTimeException("Invalid ID for region-based ZoneId, invalid format: " + zoneId);
}
ZoneRules rules = null;
try {
// always attempt load for better behavior after deserialization
rules = ZoneRulesProvider.getRules(zoneId);
rules = ZoneRulesProvider.getRules(zoneId, true);
} catch (ZoneRulesException ex) {
if (checkAvailable) {
throw ex;
@ -176,8 +178,8 @@ final class ZoneRegion extends ZoneId implements Serializable {
@Override
public ZoneRules getRules() {
// additional query for group provider when null allows for possibility
// that the provider was added after the ZoneId was created
return (rules != null ? rules : ZoneRulesProvider.getRules(id));
// that the provider was updated after the ZoneId was created
return (rules != null ? rules : ZoneRulesProvider.getRules(id, false));
}
//-----------------------------------------------------------------------

View File

@ -65,27 +65,24 @@ import static java.time.temporal.ChronoField.INSTANT_SECONDS;
import static java.time.temporal.ChronoField.NANO_OF_SECOND;
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInput;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.chrono.ChronoZonedDateTime;
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.ChronoUnit;
import java.time.temporal.ChronoZonedDateTime;
import java.time.temporal.ISOChrono;
import java.time.temporal.OffsetDateTime;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdder;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.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.ZoneOffsetTransition;
@ -152,7 +149,7 @@ import java.util.Objects;
* @since 1.8
*/
public final class ZonedDateTime
implements Temporal, ChronoZonedDateTime<ISOChrono>, Serializable {
implements Temporal, ChronoZonedDateTime<LocalDate>, Serializable {
/**
* Serialization version.
@ -225,6 +222,36 @@ public final class ZonedDateTime
}
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code ZonedDateTime} from a local date and time.
* <p>
* This creates a zoned date-time matching the input local date and time as closely as possible.
* Time-zone rules, such as daylight savings, mean that not every local date-time
* is valid for the specified zone, thus the local date-time may be adjusted.
* <p>
* The local date time and first combined to form a local date-time.
* The local date-time is then resolved to a single instant on the time-line.
* This is achieved by finding a valid offset from UTC/Greenwich for the local
* date-time as defined by the {@link ZoneRules rules} of the zone ID.
*<p>
* In most cases, there is only one valid offset for a local date-time.
* In the case of an overlap, when clocks are set back, there are two valid offsets.
* This method uses the earlier offset typically corresponding to "summer".
* <p>
* In the case of a gap, when clocks jump forward, there is no valid offset.
* Instead, the local date-time is adjusted to be later by the length of the gap.
* For a typical one hour daylight savings change, the local date-time will be
* moved one hour later into the offset typically corresponding to "summer".
*
* @param date the local date, not null
* @param time the local time, not null
* @param zone the time-zone, not null
* @return the offset date-time, not null
*/
public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone) {
return of(LocalDateTime.of(date, time), zone);
}
/**
* Obtains an instance of {@code ZonedDateTime} from a local date-time.
* <p>
@ -253,6 +280,53 @@ public final class ZonedDateTime
return ofLocal(localDateTime, zone, null);
}
/**
* Obtains an instance of {@code ZonedDateTime} from a year, month, day,
* hour, minute, second, nanosecond and time-zone.
* <p>
* This creates a zoned date-time matching the local date-time of the seven
* specified fields as closely as possible.
* Time-zone rules, such as daylight savings, mean that not every local date-time
* is valid for the specified zone, thus the local date-time may be adjusted.
* <p>
* The local date-time is resolved to a single instant on the time-line.
* This is achieved by finding a valid offset from UTC/Greenwich for the local
* date-time as defined by the {@link ZoneRules rules} of the zone ID.
*<p>
* In most cases, there is only one valid offset for a local date-time.
* In the case of an overlap, when clocks are set back, there are two valid offsets.
* This method uses the earlier offset typically corresponding to "summer".
* <p>
* In the case of a gap, when clocks jump forward, there is no valid offset.
* Instead, the local date-time is adjusted to be later by the length of the gap.
* For a typical one hour daylight savings change, the local date-time will be
* moved one hour later into the offset typically corresponding to "summer".
* <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 zone the time-zone, 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 ZonedDateTime of(
int year, int month, int dayOfMonth,
int hour, int minute, int second, int nanoOfSecond, ZoneId zone) {
LocalDateTime dt = LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond);
return ofLocal(dt, zone, null);
}
/**
* Obtains an instance of {@code ZonedDateTime} from a local date-time
* using the preferred offset if possible.
@ -436,13 +510,17 @@ public final class ZonedDateTime
/**
* Obtains an instance of {@code ZonedDateTime} from a temporal object.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code ZonedDateTime}.
* This obtains a zoned 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 ZonedDateTime}.
* <p>
* The conversion will first obtain a {@code ZoneId}. It will then try to obtain an instant.
* If that fails it will try to obtain a local date-time.
* The zoned date time will either be a combination of {@code ZoneId} and instant,
* or {@code ZoneId} and local date-time.
* The conversion will first obtain a {@code ZoneId} from the temporal object,
* falling back to a {@code ZoneOffset} if necessary. It will then try to obtain
* an {@code Instant}, falling back to a {@code LocalDateTime} if necessary.
* The result will be either the combination of {@code ZoneId} or {@code ZoneOffset}
* with {@code Instant} or {@code LocalDateTime}.
* 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 ZonedDateTime::from}.
@ -477,14 +555,14 @@ public final class ZonedDateTime
* {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
* <p>
* The string must represent a valid date-time and is parsed using
* {@link java.time.format.DateTimeFormatters#isoZonedDateTime()}.
* {@link java.time.format.DateTimeFormatter#ISO_ZONED_DATE_TIME}.
*
* @param text the text to parse such as "2007-12-03T10:15:30+01:00[Europe/Paris]", not null
* @return the parsed zoned date-time, not null
* @throws DateTimeParseException if the text cannot be parsed
*/
public static ZonedDateTime parse(CharSequence text) {
return parse(text, DateTimeFormatters.isoZonedDateTime());
return parse(text, DateTimeFormatter.ISO_ZONED_DATE_TIME);
}
/**
@ -595,7 +673,7 @@ public final class ZonedDateTime
* 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.
*
@ -604,7 +682,7 @@ public final class ZonedDateTime
*/
@Override
public boolean isSupported(TemporalField field) {
return field instanceof ChronoField || (field != null && field.doIsSupported(this));
return field instanceof ChronoField || (field != null && field.isSupportedBy(this));
}
/**
@ -621,7 +699,7 @@ public final class ZonedDateTime
* 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.
*
@ -637,7 +715,7 @@ public final class ZonedDateTime
}
return dateTime.range(field);
}
return field.doRange(this);
return field.rangeRefinedBy(this);
}
/**
@ -656,7 +734,7 @@ public final class ZonedDateTime
* 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.
*
@ -690,7 +768,7 @@ public final class ZonedDateTime
* 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.
*
@ -708,7 +786,7 @@ public final class ZonedDateTime
}
return dateTime.getLong(field);
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
@ -770,7 +848,7 @@ public final class ZonedDateTime
*/
@Override
public ZonedDateTime withLaterOffsetAtOverlap() {
ZoneOffsetTransition trans = getZone().getRules().getTransition(getDateTime());
ZoneOffsetTransition trans = getZone().getRules().getTransition(toLocalDateTime());
if (trans != null) {
ZoneOffset laterOffset = trans.getOffsetAfter();
if (laterOffset.equals(offset) == false) {
@ -859,7 +937,7 @@ public final class ZonedDateTime
* as most protocols, such as ISO-8601, only handle offsets,
* and not region-based zone IDs.
* <p>
* This is equivalent to {@code ZonedDateTime.of(zdt.getDateTime(), zdt.getOffset())}.
* This is equivalent to {@code ZonedDateTime.of(zdt.toLocalDateTime(), zdt.getOffset())}.
*
* @return a {@code ZonedDateTime} with the zone ID set to the offset, not null
*/
@ -877,7 +955,7 @@ public final class ZonedDateTime
* @return the local date-time part of this date-time, not null
*/
@Override // override for return type
public LocalDateTime getDateTime() {
public LocalDateTime toLocalDateTime() {
return dateTime;
}
@ -891,8 +969,8 @@ public final class ZonedDateTime
* @return the date part of this date-time, not null
*/
@Override // override for return type
public LocalDate getDate() {
return dateTime.getDate();
public LocalDate toLocalDate() {
return dateTime.toLocalDate();
}
/**
@ -901,7 +979,7 @@ public final class ZonedDateTime
* 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
*/
@ -987,8 +1065,8 @@ public final class ZonedDateTime
* @return the time part of this date-time, not null
*/
@Override // override for Javadoc and performance
public LocalTime getTime() {
return dateTime.getTime();
public LocalTime toLocalTime() {
return dateTime.toLocalTime();
}
/**
@ -1031,7 +1109,7 @@ public final class ZonedDateTime
/**
* Returns an adjusted copy of this date-time.
* <p>
* This returns a new {@code ZonedDateTime}, based on this one, with the date-time adjusted.
* This returns a {@code ZonedDateTime}, based on this one, with the date-time adjusted.
* The adjustment takes place using the specified adjuster strategy object.
* Read the documentation of the adjuster to understand what adjustment will be made.
* <p>
@ -1040,7 +1118,7 @@ public final class ZonedDateTime
* 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>
@ -1084,9 +1162,9 @@ public final class ZonedDateTime
public ZonedDateTime with(TemporalAdjuster adjuster) {
// optimizations
if (adjuster instanceof LocalDate) {
return resolveLocal(LocalDateTime.of((LocalDate) adjuster, dateTime.getTime()));
return resolveLocal(LocalDateTime.of((LocalDate) adjuster, dateTime.toLocalTime()));
} else if (adjuster instanceof LocalTime) {
return resolveLocal(LocalDateTime.of(dateTime.getDate(), (LocalTime) adjuster));
return resolveLocal(LocalDateTime.of(dateTime.toLocalDate(), (LocalTime) adjuster));
} else if (adjuster instanceof LocalDateTime) {
return resolveLocal((LocalDateTime) adjuster);
} else if (adjuster instanceof Instant) {
@ -1101,7 +1179,7 @@ public final class ZonedDateTime
/**
* Returns a copy of this date-time with the specified field set to a new value.
* <p>
* This returns a new {@code ZonedDateTime}, based on this one, with the value
* This returns a {@code ZonedDateTime}, based on this one, with the value
* for the specified field changed.
* This can be used to change any supported field, such as the year, month or day-of-month.
* If it is not possible to set the value, because the field is not supported or for
@ -1139,7 +1217,7 @@ public final class ZonedDateTime
* 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>
@ -1164,7 +1242,7 @@ public final class ZonedDateTime
}
return resolveLocal(dateTime.with(field, newValue));
}
return field.doWith(this, newValue);
return field.adjustInto(this, newValue);
}
//-----------------------------------------------------------------------
@ -1228,8 +1306,8 @@ public final class ZonedDateTime
*
* @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31
* @return a {@code ZonedDateTime} based on this date-time with the requested day, not null
* @throws DateTimeException if the day-of-month value is invalid
* @throws DateTimeException if the day-of-month is invalid for the month-year
* @throws DateTimeException if the day-of-month value is invalid,
* or if the day-of-month is invalid for the month-year
*/
public ZonedDateTime withDayOfMonth(int dayOfMonth) {
return resolveLocal(dateTime.withDayOfMonth(dayOfMonth));
@ -1251,8 +1329,8 @@ public final class ZonedDateTime
*
* @param dayOfYear the day-of-year to set in the result, from 1 to 365-366
* @return a {@code ZonedDateTime} based on this date with the requested day, not null
* @throws DateTimeException if the day-of-year value is invalid
* @throws DateTimeException if the day-of-year is invalid for the year
* @throws DateTimeException if the day-of-year value is invalid,
* or if the day-of-year is invalid for the year
*/
public ZonedDateTime withDayOfYear(int dayOfYear) {
return resolveLocal(dateTime.withDayOfYear(dayOfYear));
@ -1356,8 +1434,10 @@ public final class ZonedDateTime
* 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 operates on the local time-line,
* {@link LocalDateTime#truncatedTo(java.time.temporal.TemporalUnit) truncating}
@ -1380,34 +1460,39 @@ public final class ZonedDateTime
//-----------------------------------------------------------------------
/**
* 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 ZonedDateTime}, 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 ZonedDateTime} based on this date-time with the addition made, not null
* @throws DateTimeException if the addition cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public ZonedDateTime plus(TemporalAdder adder) {
return (ZonedDateTime) adder.addTo(this);
public ZonedDateTime plus(TemporalAmount amountToAdd) {
return (ZonedDateTime) 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 ZonedDateTime}, 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 zone is not part of the calculation and will be unchanged in the result.
* The calculation for date and time units differ.
* <p>
* Date units operate on the local time-line.
@ -1422,12 +1507,18 @@ public final class ZonedDateTime
* The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}
* with the offset before the addition.
* <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 ZonedDateTime} 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 ZonedDateTime} 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 ZonedDateTime plus(long amountToAdd, TemporalUnit unit) {
@ -1439,7 +1530,7 @@ public final class ZonedDateTime
return resolveInstant(dateTime.plus(amountToAdd, unit));
}
}
return unit.doPlus(this, amountToAdd);
return unit.addTo(this, amountToAdd);
}
//-----------------------------------------------------------------------
@ -1616,33 +1707,36 @@ public final class ZonedDateTime
//-----------------------------------------------------------------------
/**
* 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 ZonedDateTime}, 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 ZonedDateTime} based on this date-time with the subtraction made, not null
* @throws DateTimeException if the subtraction cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public ZonedDateTime minus(TemporalSubtractor subtractor) {
return (ZonedDateTime) subtractor.subtractFrom(this);
public ZonedDateTime minus(TemporalAmount amountToSubtract) {
return (ZonedDateTime) 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 ZonedDateTime}, 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>
* The calculation for date and time units differ.
* <p>
@ -1658,12 +1752,16 @@ public final class ZonedDateTime
* The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}
* with the offset before the subtraction.
* <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 ZonedDateTime} 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 ZonedDateTime} 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 ZonedDateTime minus(long amountToSubtract, TemporalUnit unit) {
@ -1885,14 +1983,15 @@ public final class ZonedDateTime
* For example, the period in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z
* will only be one month as it is one minute short of two months.
* <p>
* This method operates in association with {@link TemporalUnit#between}.
* The result of this method is a {@code long} representing the amount of
* the specified unit. By contrast, the result of {@code between} is an
* object that can be used directly in addition/subtraction:
* 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},
@ -1944,7 +2043,7 @@ public final class ZonedDateTime
return toOffsetDateTime().periodUntil(end.toOffsetDateTime(), unit);
}
}
return unit.between(this, endDateTime).getAmount();
return unit.between(this, endDateTime);
}
//-----------------------------------------------------------------------
@ -2018,7 +2117,7 @@ public final class ZonedDateTime
* Outputs this date-time as a {@code String} using the formatter.
* <p>
* This date will be passed to the formatter
* {@link DateTimeFormatter#print(TemporalAccessor) print method}.
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted date-time string, not null
@ -2061,7 +2160,7 @@ public final class ZonedDateTime
zone.write(out);
}
static ZonedDateTime readExternal(DataInput in) throws IOException {
static ZonedDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
LocalDateTime dateTime = LocalDateTime.readExternal(in);
ZoneOffset offset = ZoneOffset.readExternal(in);
ZoneId zone = (ZoneId) Ser.read(in);

View File

@ -1,106 +0,0 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of JSR-310 nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* <p>
* Support for calendar systems other than the default ISO.
* </p>
* <p>
* The main API is based around the calendar system defined in ISO-8601.
* This package provides support for alternate systems.
* </p>
* <p>
* The supported calendar systems includes:
* </p>
* <ul>
* <li>{@link java.time.calendar.HijrahChrono Hijrah calendar}</li>
* <li>{@link java.time.calendar.JapaneseChrono Japanese calendar}</li>
* <li>{@link java.time.calendar.MinguoChrono Minguo calendar}</li>
* <li>{@link java.time.calendar.ThaiBuddhistChrono Thai Buddhist calendar}</li>
* </ul>
* <p>
* It is intended that applications use the main API whenever possible,
* including code to read and write from a persistent data store,
* such as a database, and to send dates and times across a network.
* This package is then used at the user interface level to deal with
* localized input/output.
* See {@link java.time.temporal.ChronoLocalDate ChronoLocalDate}
* for a full discussion of the issues.
* </p>
*
* <h3>Example</h3>
* <p>
* This example creates and uses a date in a non-ISO calendar system.
* </p>
* <pre>
* // Print the Thai Buddhist date
* ChronoLocalDate&lt;ThaiBuddhistChrono&gt; now1 = ThaiBuddhistChrono.INSTANCE.dateNow();
* int day = now1.get(ChronoField.DAY_OF_MONTH);
* int dow = now1.get(ChronoField.DAY_OF_WEEK);
* int month = now1.get(ChronoField.MONTH_OF_YEAR);
* int year = now1.get(ChronoField.YEAR);
* System.out.printf(" Today is %s %s %d-%s-%d%n", now1.getChrono().getId(),
* dow, day, month, year);
*
* // Enumerate the list of available calendars and print today for each
* Set&lt;Chrono&lt;?&gt;&gt; chronos = Chrono.getAvailableChronologies();
* for (Chrono&lt;?&gt; chrono : chronos) {
* ChronoLocalDate&lt;?&gt; date = chrono.dateNow();
* System.out.printf(" %20s: %s%n", chrono.getId(), date.toString());
* }
*
* // Print today's date and the last day of the year for the Thai Buddhist Calendar.
* ChronoLocalDate&lt;ThaiBuddhistChrono&gt; first = now1
* .with(ChronoField.DAY_OF_MONTH, 1)
* .with(ChronoField.MONTH_OF_YEAR, 1);
* ChronoLocalDate&lt;ThaiBuddhistChrono&gt; last = first
* .plus(1, ChronoUnit.YEARS)
* .minus(1, ChronoUnit.DAYS);
* System.out.printf(" %s: 1st of year: %s; end of year: %s%n", last.getChrono().getId(),
* first, last);
* </pre>
*
* <h3>Package specification</h3>
* <p>
* Unless otherwise noted, passing a null argument to a constructor or method in any class or interface
* in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown.
* The Javadoc "@param" definition is used to summarise the null-behavior.
* The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method.
* </p>
* <p>
* All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
* or a {@link java.time.DateTimeException}.
* </p>
* @since JDK1.8
*/
package java.time.calendar;

View File

@ -54,7 +54,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.ERA;
@ -65,9 +65,9 @@ import java.io.Serializable;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.temporal.Chrono;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.ChronoLocalDateTime;
import java.time.chrono.Chronology;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.ChronoLocalDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
@ -80,7 +80,7 @@ import java.time.temporal.TemporalUnit;
* For example, the Japanese, Minguo, Thai Buddhist and others.
* <p>
* {@code ChronoLocalDate} is built on the generic concepts of year, month and day.
* The calendar system, represented by a {@link java.time.temporal.Chrono}, expresses the relationship between
* The calendar system, represented by a {@link java.time.chrono.Chronology}, expresses the relationship between
* the fields and this class allows the resulting date to be manipulated.
* <p>
* Note that not all calendar systems are suitable for use with this class.
@ -95,52 +95,52 @@ import java.time.temporal.TemporalUnit;
* <pre>
* System.out.printf("Example()%n");
* // Enumerate the list of available calendars and print today for each
* Set&lt;Chrono&gt; chronos = Chrono.getAvailableChronologies();
* for (Chrono chrono : chronos) {
* Set&lt;Chronology&gt; chronos = Chronology.getAvailableChronologies();
* for (Chronology chrono : chronos) {
* ChronoLocalDate<?> date = chrono.dateNow();
* System.out.printf(" %20s: %s%n", chrono.getID(), date.toString());
* }
*
* // Print the Hijrah date and calendar
* ChronoLocalDate<?> date = Chrono.of("Hijrah").dateNow();
* ChronoLocalDate<?> date = Chronology.of("Hijrah").dateNow();
* int day = date.get(ChronoField.DAY_OF_MONTH);
* int dow = date.get(ChronoField.DAY_OF_WEEK);
* int month = date.get(ChronoField.MONTH_OF_YEAR);
* int year = date.get(ChronoField.YEAR);
* System.out.printf(" Today is %s %s %d-%s-%d%n", date.getChrono().getID(),
* System.out.printf(" Today is %s %s %d-%s-%d%n", date.getChronology().getID(),
* dow, day, month, year);
* // Print today's date and the last day of the year
* ChronoLocalDate<?> now1 = Chrono.of("Hijrah").dateNow();
* ChronoLocalDate<?> now1 = Chronology.of("Hijrah").dateNow();
* ChronoLocalDate<?> first = now1.with(ChronoField.DAY_OF_MONTH, 1)
* .with(ChronoField.MONTH_OF_YEAR, 1);
* ChronoLocalDate<?> last = first.plus(1, ChronoUnit.YEARS)
* .minus(1, ChronoUnit.DAYS);
* System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChrono().getID(),
* System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChronology().getID(),
* first, last);
* </pre>
*
* <h3>Adding Calendars</h3>
* <p> The set of calendars is extensible by defining a subclass of {@link ChronoLocalDate}
* to represent a date instance and an implementation of {@code Chrono}
* to represent a date instance and an implementation of {@code Chronology}
* to be the factory for the ChronoLocalDate subclass.
* </p>
* <p> To permit the discovery of the additional calendar types the implementation of
* {@code Chrono} must be registered as a Service implementing the {@code Chrono} interface
* {@code Chronology} must be registered as a Service implementing the {@code Chronology} interface
* in the {@code META-INF/Services} file as per the specification of {@link java.util.ServiceLoader}.
* The subclass must function according to the {@code Chrono} class description and must provide its
* {@link java.time.temporal.Chrono#getId() chronlogy ID} and {@link Chrono#getCalendarType() calendar type}. </p>
* The subclass must function according to the {@code Chronology} class description and must provide its
* {@link java.time.chrono.Chronology#getId() chronlogy ID} and {@link Chronology#getCalendarType() calendar type}. </p>
*
* <h3>Specification for implementors</h3>
* This abstract class must be implemented with care to ensure other classes operate correctly.
* All implementations that can be instantiated must be final, immutable and thread-safe.
* Subclasses should be Serializable wherever possible.
*
* @param <C> the chronology of this date
* @param <D> the ChronoLocalDate of this date-time
* @since 1.8
*/
abstract class ChronoDateImpl<C extends Chrono<C>>
implements ChronoLocalDate<C>, Temporal, TemporalAdjuster, Serializable {
abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
implements ChronoLocalDate<D>, Temporal, TemporalAdjuster, Serializable {
/**
* Serialization version.
@ -155,7 +155,7 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
//-----------------------------------------------------------------------
@Override
public ChronoLocalDate<C> plus(long amountToAdd, TemporalUnit unit) {
public D plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
ChronoUnit f = (ChronoUnit) unit;
switch (f) {
@ -188,7 +188,7 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
* @return a date based on this one with the years added, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
abstract ChronoDateImpl<C> plusYears(long yearsToAdd);
abstract D plusYears(long yearsToAdd);
/**
* Returns a copy of this date with the specified period in months added.
@ -204,7 +204,7 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
* @return a date based on this one with the months added, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
abstract ChronoDateImpl<C> plusMonths(long monthsToAdd);
abstract D plusMonths(long monthsToAdd);
/**
* Returns a copy of this date with the specified period in weeks added.
@ -221,7 +221,7 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
* @return a date based on this one with the weeks added, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
ChronoDateImpl<C> plusWeeks(long weeksToAdd) {
D plusWeeks(long weeksToAdd) {
return plusDays(Math.multiplyExact(weeksToAdd, 7));
}
@ -236,7 +236,7 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
* @return a date based on this one with the days added, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
abstract ChronoDateImpl<C> plusDays(long daysToAdd);
abstract D plusDays(long daysToAdd);
//-----------------------------------------------------------------------
/**
@ -255,8 +255,8 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
* @return a date based on this one with the years subtracted, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
ChronoDateImpl<C> minusYears(long yearsToSubtract) {
return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
D minusYears(long yearsToSubtract) {
return (yearsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl<D>)plusYears(Long.MAX_VALUE)).plusYears(1) : plusYears(-yearsToSubtract));
}
/**
@ -275,8 +275,8 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
* @return a date based on this one with the months subtracted, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
ChronoDateImpl<C> minusMonths(long monthsToSubtract) {
return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
D minusMonths(long monthsToSubtract) {
return (monthsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl<D>)plusMonths(Long.MAX_VALUE)).plusMonths(1) : plusMonths(-monthsToSubtract));
}
/**
@ -294,8 +294,8 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
* @return a date based on this one with the weeks subtracted, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
ChronoDateImpl<C> minusWeeks(long weeksToSubtract) {
return (weeksToSubtract == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeksToSubtract));
D minusWeeks(long weeksToSubtract) {
return (weeksToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl<D>)plusWeeks(Long.MAX_VALUE)).plusWeeks(1) : plusWeeks(-weeksToSubtract));
}
/**
@ -311,13 +311,8 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
* @return a date based on this one with the days subtracted, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
ChronoDateImpl<C> minusDays(long daysToSubtract) {
return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
}
@Override
public final ChronoLocalDateTime<C> atTime(LocalTime localTime) {
return Chrono.dateTime(this, localTime);
D minusDays(long daysToSubtract) {
return (daysToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl<D>)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract));
}
//-----------------------------------------------------------------------
@ -332,13 +327,13 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
throw new DateTimeException("Unable to calculate period between objects of two different types");
}
ChronoLocalDate<?> end = (ChronoLocalDate<?>) endDateTime;
if (getChrono().equals(end.getChrono()) == false) {
if (getChronology().equals(end.getChronology()) == false) {
throw new DateTimeException("Unable to calculate period between two different chronologies");
}
if (unit instanceof ChronoUnit) {
return LocalDate.from(this).periodUntil(end, unit); // TODO: this is wrong
}
return unit.between(this, endDateTime).getAmount();
return unit.between(this, endDateTime);
}
@Override
@ -355,7 +350,7 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
@Override
public int hashCode() {
long epDay = toEpochDay();
return getChrono().hashCode() ^ ((int) (epDay ^ (epDay >>> 32)));
return getChronology().hashCode() ^ ((int) (epDay ^ (epDay >>> 32)));
}
@Override
@ -365,7 +360,7 @@ abstract class ChronoDateImpl<C extends Chrono<C>>
long moy = getLong(MONTH_OF_YEAR);
long dom = getLong(DAY_OF_MONTH);
StringBuilder buf = new StringBuilder(30);
buf.append(getChrono().toString())
buf.append(getChronology().toString())
.append(" ")
.append(getEra())
.append(" ")

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time.chrono;
import static java.time.temporal.ChronoField.EPOCH_DAY;
import static java.time.temporal.ChronoField.ERA;
@ -69,7 +69,18 @@ import static java.time.temporal.ChronoUnit.DAYS;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
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.util.Comparator;
import java.util.Objects;
@ -81,7 +92,7 @@ import java.util.Objects;
* as {@link LocalDate}, not this interface.</b>
* <p>
* A {@code ChronoLocalDate} is the abstract representation of a date where the
* {@code Chrono chronology}, or calendar system, is pluggable.
* {@code Chronology chronology}, or calendar system, is pluggable.
* The date is defined in terms of fields expressed by {@link TemporalField},
* where most common implementations are defined in {@link ChronoField}.
* The chronology defines how the calendar system operates and the meaning of
@ -93,7 +104,7 @@ import java.util.Objects;
* calendar systems. The rationale for this is explored in the following documentation.
* <p>
* The primary use case where this interface should be used is where the generic
* type parameter {@code <C>} is fully defined as a specific chronology.
* type parameter {@code <D>} is fully defined as a specific chronology.
* In that case, the assumptions of that chronology are known at development
* time and specified in the code.
* <p>
@ -229,12 +240,12 @@ import java.util.Objects;
* Subclasses should be Serializable wherever possible.
* <p>
* Additional calendar systems may be added to the system.
* See {@link Chrono} for more details.
* See {@link Chronology} for more details.
*
* @param <C> the chronology of this date
* @param <D> the concrete type for the date
* @since 1.8
*/
public interface ChronoLocalDate<C extends Chrono<C>>
public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDate<?>> {
/**
@ -262,12 +273,12 @@ public interface ChronoLocalDate<C extends Chrono<C>>
/**
* Gets the chronology of this date.
* <p>
* The {@code Chrono} represents the calendar system in use.
* The {@code Chronology} represents the calendar system in use.
* The era and other fields in {@link ChronoField} are defined by the chronology.
*
* @return the chronology, not null
*/
C getChrono();
Chronology getChronology();
/**
* Gets the era, as defined by the chronology.
@ -275,17 +286,17 @@ public interface ChronoLocalDate<C extends Chrono<C>>
* The era is, conceptually, the largest division of the time-line.
* Most calendar systems have a single epoch dividing the time-line into two eras.
* However, some have multiple eras, such as one for the reign of each leader.
* The exact meaning is determined by the {@code Chrono}.
* The exact meaning is determined by the {@code Chronology}.
* <p>
* All correctly implemented {@code Era} classes are singletons, thus it
* is valid code to write {@code date.getEra() == SomeChrono.ERA_NAME)}.
* <p>
* This default implementation uses {@link Chrono#eraOf(int)}.
* This default implementation uses {@link Chronology#eraOf(int)}.
*
* @return the chronology specific era constant applicable at this date, not null
*/
public default Era<C> getEra() {
return getChrono().eraOf(get(ERA));
public default Era getEra() {
return getChronology().eraOf(get(ERA));
}
/**
@ -295,12 +306,12 @@ public interface ChronoLocalDate<C extends Chrono<C>>
* The exact meaning is determined by the chronology with the constraint that
* a leap-year must imply a year-length longer than a non leap-year.
* <p>
* This default implementation uses {@link Chrono#isLeapYear(long)}.
* This default implementation uses {@link Chronology#isLeapYear(long)}.
*
* @return true if this date is in a leap year, false otherwise
*/
public default boolean isLeapYear() {
return getChrono().isLeapYear(getLong(YEAR));
return getChronology().isLeapYear(getLong(YEAR));
}
/**
@ -330,7 +341,7 @@ public interface ChronoLocalDate<C extends Chrono<C>>
if (field instanceof ChronoField) {
return ((ChronoField) field).isDateField();
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
//-----------------------------------------------------------------------
@ -341,8 +352,8 @@ public interface ChronoLocalDate<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoLocalDate<C> with(TemporalAdjuster adjuster) {
return getChrono().ensureChronoLocalDate(Temporal.super.with(adjuster));
public default D with(TemporalAdjuster adjuster) {
return (D) getChronology().ensureChronoLocalDate(Temporal.super.with(adjuster));
}
/**
@ -351,11 +362,11 @@ public interface ChronoLocalDate<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoLocalDate<C> with(TemporalField field, long newValue) {
public default D with(TemporalField field, long newValue) {
if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return getChrono().ensureChronoLocalDate(field.doWith(this, newValue));
return (D) getChronology().ensureChronoLocalDate(field.adjustInto(this, newValue));
}
/**
@ -364,8 +375,8 @@ public interface ChronoLocalDate<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoLocalDate<C> plus(TemporalAdder adder) {
return getChrono().ensureChronoLocalDate(Temporal.super.plus(adder));
public default D plus(TemporalAmount amount) {
return (D) getChronology().ensureChronoLocalDate(Temporal.super.plus(amount));
}
/**
@ -374,11 +385,11 @@ public interface ChronoLocalDate<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoLocalDate<C> plus(long amountToAdd, TemporalUnit unit) {
public default D plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
return getChrono().ensureChronoLocalDate(unit.doPlus(this, amountToAdd));
return (D) getChronology().ensureChronoLocalDate(unit.addTo(this, amountToAdd));
}
/**
@ -387,8 +398,8 @@ public interface ChronoLocalDate<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoLocalDate<C> minus(TemporalSubtractor subtractor) {
return getChrono().ensureChronoLocalDate(Temporal.super.minus(subtractor));
public default D minus(TemporalAmount amount) {
return (D) getChronology().ensureChronoLocalDate(Temporal.super.minus(amount));
}
/**
@ -397,8 +408,8 @@ public interface ChronoLocalDate<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoLocalDate<C> minus(long amountToSubtract, TemporalUnit unit) {
return getChrono().ensureChronoLocalDate(Temporal.super.minus(amountToSubtract, unit));
public default D minus(long amountToSubtract, TemporalUnit unit) {
return (D) getChronology().ensureChronoLocalDate(Temporal.super.minus(amountToSubtract, unit));
}
//-----------------------------------------------------------------------
@ -423,16 +434,17 @@ public interface ChronoLocalDate<C extends Chrono<C>>
@SuppressWarnings("unchecked")
@Override
public default <R> R query(TemporalQuery<R> query) {
if (query == Queries.chrono()) {
return (R) getChrono();
}
if (query == Queries.precision()) {
if (query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
return null;
} else if (query == Queries.localTime()) {
return null;
} else if (query == Queries.chronology()) {
return (R) getChronology();
} else if (query == Queries.precision()) {
return (R) DAYS;
}
// inline TemporalAccessor.super.query(query) as an optimization
if (query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
return null;
}
// non-JDK classes are not permitted to make this optimization
return query.queryFrom(this);
}
@ -479,14 +491,15 @@ public interface ChronoLocalDate<C extends Chrono<C>>
* For example, the period in days between two dates can be calculated
* using {@code startDate.periodUntil(endDate, DAYS)}.
* <p>
* This method operates in association with {@link TemporalUnit#between}.
* The result of this method is a {@code long} representing the amount of
* the specified unit. By contrast, the result of {@code between} is an
* object that can be used directly in addition/subtraction:
* 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},
@ -511,22 +524,40 @@ public interface ChronoLocalDate<C extends Chrono<C>>
@Override // override for Javadoc
public abstract long periodUntil(Temporal endDate, TemporalUnit unit);
//-----------------------------------------------------------------------
/**
* Returns a date-time formed from this date at the specified time.
* Calculates the period between this date and another date as a {@code Period}.
* <p>
* This merges the two objects - {@code this} and the specified time -
* to form an instance of {@code ChronoLocalDateTime}.
* 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 the chronology of this date.
* If necessary, the input date will be converted to match.
* <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>
* This instance is immutable and unaffected by this method call.
*
* @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
* @throws DateTimeException if the period cannot be calculated
* @throws ArithmeticException if numeric overflow occurs
*/
public abstract Period periodUntil(ChronoLocalDate<?> endDate);
//-----------------------------------------------------------------------
/**
* Combines this date with a time to create a {@code ChronoLocalDateTime}.
* <p>
* This default implementation creates the date-time.
* This returns a {@code ChronoLocalDateTime} formed from this date at the specified time.
* All possible combinations of date and time are valid.
*
* @param localTime the local time to use, not null
* @return the local date-time formed from this date and the specified time, not null
*/
public default ChronoLocalDateTime<C> atTime(LocalTime localTime) {
return Chrono.dateTime(this, localTime);
public default ChronoLocalDateTime<D> atTime(LocalTime localTime) {
return (ChronoLocalDateTime<D>)ChronoLocalDateTimeImpl.of(this, localTime);
}
//-----------------------------------------------------------------------
@ -578,7 +609,7 @@ public interface ChronoLocalDate<C extends Chrono<C>>
public default int compareTo(ChronoLocalDate<?> other) {
int cmp = Long.compare(toEpochDay(), other.toEpochDay());
if (cmp == 0) {
cmp = getChrono().compareTo(other.getChrono());
cmp = getChronology().compareTo(other.getChronology());
}
return cmp;
}
@ -676,7 +707,7 @@ public interface ChronoLocalDate<C extends Chrono<C>>
* <p>
* The default implementation must behave as follows:
* <pre>
* return formatter.print(this);
* return formatter.format(this);
* </pre>
*
* @param formatter the formatter to use, not null
@ -685,7 +716,7 @@ public interface ChronoLocalDate<C extends Chrono<C>>
*/
public default String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.print(this);
return formatter.format(this);
}
}

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time.chrono;
import static java.time.temporal.ChronoField.EPOCH_DAY;
import static java.time.temporal.ChronoField.NANO_OF_DAY;
@ -72,6 +72,15 @@ import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
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.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.zone.ZoneRules;
import java.util.Comparator;
import java.util.Objects;
@ -84,7 +93,7 @@ import java.util.Objects;
* as {@link LocalDateTime}, not this interface.</b>
* <p>
* A {@code ChronoLocalDateTime} is the abstract representation of a local date-time
* where the {@code Chrono chronology}, or calendar system, is pluggable.
* where the {@code Chronology chronology}, or calendar system, is pluggable.
* The date-time is defined in terms of fields expressed by {@link TemporalField},
* where most common implementations are defined in {@link ChronoField}.
* The chronology defines how the calendar system operates and the meaning of
@ -103,10 +112,10 @@ import java.util.Objects;
* All implementations that can be instantiated must be final, immutable and thread-safe.
* Subclasses should be Serializable wherever possible.
*
* @param <C> the chronology of this date-time
* @param <D> the concrete type for the date of this date-time
* @since 1.8
*/
public interface ChronoLocalDateTime<C extends Chrono<C>>
public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>>
extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDateTime<?>> {
/**
@ -125,9 +134,9 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
new Comparator<ChronoLocalDateTime<?>>() {
@Override
public int compare(ChronoLocalDateTime<?> datetime1, ChronoLocalDateTime<?> datetime2) {
int cmp = Long.compare(datetime1.getDate().toEpochDay(), datetime2.getDate().toEpochDay());
int cmp = Long.compare(datetime1.toLocalDate().toEpochDay(), datetime2.toLocalDate().toEpochDay());
if (cmp == 0) {
cmp = Long.compare(datetime1.getTime().toNanoOfDay(), datetime2.getTime().toNanoOfDay());
cmp = Long.compare(datetime1.toLocalTime().toNanoOfDay(), datetime2.toLocalTime().toNanoOfDay());
}
return cmp;
}
@ -141,7 +150,7 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
*
* @return the date part of this date-time, not null
*/
ChronoLocalDate<C> getDate() ;
D toLocalDate() ;
/**
* Gets the local time part of this date-time.
@ -151,8 +160,10 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
*
* @return the time part of this date-time, not null
*/
LocalTime getTime();
LocalTime toLocalTime();
@Override // Override to provide javadoc
public boolean isSupported(TemporalField field);
//-----------------------------------------------------------------------
// override for covariant return type
@ -162,8 +173,8 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoLocalDateTime<C> with(TemporalAdjuster adjuster) {
return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.with(adjuster));
public default ChronoLocalDateTime<D> with(TemporalAdjuster adjuster) {
return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.with(adjuster)));
}
/**
@ -172,7 +183,7 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
ChronoLocalDateTime<C> with(TemporalField field, long newValue);
ChronoLocalDateTime<D> with(TemporalField field, long newValue);
/**
* {@inheritDoc}
@ -180,8 +191,8 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoLocalDateTime<C> plus(TemporalAdder adder) {
return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.plus(adder));
public default ChronoLocalDateTime<D> plus(TemporalAmount amount) {
return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.plus(amount)));
}
/**
@ -190,7 +201,7 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
ChronoLocalDateTime<C> plus(long amountToAdd, TemporalUnit unit);
ChronoLocalDateTime<D> plus(long amountToAdd, TemporalUnit unit);
/**
* {@inheritDoc}
@ -198,8 +209,8 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoLocalDateTime<C> minus(TemporalSubtractor subtractor) {
return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.minus(subtractor));
public default ChronoLocalDateTime<D> minus(TemporalAmount amount) {
return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amount)));
}
/**
@ -208,8 +219,8 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoLocalDateTime<C> minus(long amountToSubtract, TemporalUnit unit) {
return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.minus(amountToSubtract, unit));
public default ChronoLocalDateTime<D> minus(long amountToSubtract, TemporalUnit unit) {
return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amountToSubtract, unit)));
}
//-----------------------------------------------------------------------
@ -234,16 +245,17 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
@SuppressWarnings("unchecked")
@Override
public default <R> R query(TemporalQuery<R> query) {
if (query == Queries.chrono()) {
return (R) getDate().getChrono();
}
if (query == Queries.precision()) {
if (query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
return null;
} else if (query == Queries.localTime()) {
return (R) toLocalTime();
} else if (query == Queries.chronology()) {
return (R) toLocalDate().getChronology();
} else if (query == Queries.precision()) {
return (R) NANOS;
}
// inline TemporalAccessor.super.query(query) as an optimization
if (query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
return null;
}
// non-JDK classes are not permitted to make this optimization
return query.queryFrom(this);
}
@ -275,15 +287,16 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
@Override
public default Temporal adjustInto(Temporal temporal) {
return temporal
.with(EPOCH_DAY, getDate().toEpochDay())
.with(NANO_OF_DAY, getTime().toNanoOfDay());
.with(EPOCH_DAY, toLocalDate().toEpochDay())
.with(NANO_OF_DAY, toLocalTime().toNanoOfDay());
}
//-----------------------------------------------------------------------
/**
* 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 ChronoZonedDateTime}.
* <p>
* This creates a zoned date-time matching the input date-time as closely as possible.
* This returns a {@code ChronoZonedDateTime} 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>
@ -302,13 +315,11 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* <p>
* To obtain the later offset during an overlap, call
* {@link ChronoZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param zone the time-zone to use, not null
* @return the zoned date-time formed from this date-time, not null
*/
ChronoZonedDateTime<C> atZone(ZoneId zone);
ChronoZonedDateTime<D> atZone(ZoneId zone);
//-----------------------------------------------------------------------
/**
@ -324,7 +335,7 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* @return an {@code Instant} representing the same instant, not null
*/
public default Instant toInstant(ZoneOffset offset) {
return Instant.ofEpochSecond(toEpochSecond(offset), getTime().getNano());
return Instant.ofEpochSecond(toEpochSecond(offset), toLocalTime().getNano());
}
/**
@ -343,8 +354,8 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
*/
public default long toEpochSecond(ZoneOffset offset) {
Objects.requireNonNull(offset, "offset");
long epochDay = getDate().toEpochDay();
long secs = epochDay * 86400 + getTime().toSecondOfDay();
long epochDay = toLocalDate().toEpochDay();
long secs = epochDay * 86400 + toLocalTime().toSecondOfDay();
secs -= offset.getTotalSeconds();
return secs;
}
@ -378,11 +389,11 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
*/
@Override
public default int compareTo(ChronoLocalDateTime<?> other) {
int cmp = getDate().compareTo(other.getDate());
int cmp = toLocalDate().compareTo(other.toLocalDate());
if (cmp == 0) {
cmp = getTime().compareTo(other.getTime());
cmp = toLocalTime().compareTo(other.toLocalTime());
if (cmp == 0) {
cmp = getDate().getChrono().compareTo(other.getDate().getChrono());
cmp = toLocalDate().getChronology().compareTo(other.toLocalDate().getChronology());
}
}
return cmp;
@ -403,10 +414,10 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* @return true if this is after the specified date-time
*/
public default boolean isAfter(ChronoLocalDateTime<?> other) {
long thisEpDay = this.getDate().toEpochDay();
long otherEpDay = other.getDate().toEpochDay();
long thisEpDay = this.toLocalDate().toEpochDay();
long otherEpDay = other.toLocalDate().toEpochDay();
return thisEpDay > otherEpDay ||
(thisEpDay == otherEpDay && this.getTime().toNanoOfDay() > other.getTime().toNanoOfDay());
(thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() > other.toLocalTime().toNanoOfDay());
}
/**
@ -424,10 +435,10 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* @return true if this is before the specified date-time
*/
public default boolean isBefore(ChronoLocalDateTime<?> other) {
long thisEpDay = this.getDate().toEpochDay();
long otherEpDay = other.getDate().toEpochDay();
long thisEpDay = this.toLocalDate().toEpochDay();
long otherEpDay = other.toLocalDate().toEpochDay();
return thisEpDay < otherEpDay ||
(thisEpDay == otherEpDay && this.getTime().toNanoOfDay() < other.getTime().toNanoOfDay());
(thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() < other.toLocalTime().toNanoOfDay());
}
/**
@ -446,8 +457,8 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
*/
public default boolean isEqual(ChronoLocalDateTime<?> other) {
// Do the time check first, it is cheaper than computing EPOCH day.
return this.getTime().toNanoOfDay() == other.getTime().toNanoOfDay() &&
this.getDate().toEpochDay() == other.getDate().toEpochDay();
return this.toLocalTime().toNanoOfDay() == other.toLocalTime().toNanoOfDay() &&
this.toLocalDate().toEpochDay() == other.toLocalDate().toEpochDay();
}
/**
@ -485,7 +496,7 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
* <p>
* The default implementation must behave as follows:
* <pre>
* return formatter.print(this);
* return formatter.format(this);
* </pre>
*
* @param formatter the formatter to use, not null
@ -494,6 +505,6 @@ public interface ChronoLocalDateTime<C extends Chrono<C>>
*/
public default String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.print(this);
return formatter.format(this);
}
}

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time.chrono;
import static java.time.temporal.ChronoField.EPOCH_DAY;
@ -72,6 +72,13 @@ import java.io.Serializable;
import java.time.DateTimeException;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.util.Objects;
/**
@ -88,11 +95,11 @@ import java.util.Objects;
* <h3>Specification for implementors</h3>
* This class is immutable and thread-safe.
*
* @param <C> the chronology of this date
* @param <D> the concrete type for the date of this date-time
* @since 1.8
*/
final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
implements ChronoLocalDateTime<C>, Temporal, TemporalAdjuster, Serializable {
final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
implements ChronoLocalDateTime<D>, Temporal, TemporalAdjuster, Serializable {
/**
* Serialization version.
@ -150,7 +157,7 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
/**
* The date part.
*/
private final ChronoLocalDate<C> date;
private final D date;
/**
* The time part.
*/
@ -164,8 +171,8 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
* @param time the local time, not null
* @return the local date-time, not null
*/
static <R extends Chrono<R>> ChronoLocalDateTimeImpl<R> of(ChronoLocalDate<R> date, LocalTime time) {
return new ChronoLocalDateTimeImpl<>(date, time);
static ChronoLocalDateTimeImpl<?> of(ChronoLocalDate<?> date, LocalTime time) {
return new ChronoLocalDateTimeImpl(date, time);
}
/**
@ -174,7 +181,7 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
* @param date the date part of the date-time, not null
* @param time the time part of the date-time, not null
*/
private ChronoLocalDateTimeImpl(ChronoLocalDate<C> date, LocalTime time) {
private ChronoLocalDateTimeImpl(D date, LocalTime time) {
Objects.requireNonNull(date, "date");
Objects.requireNonNull(time, "time");
this.date = date;
@ -189,23 +196,23 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
* @param newTime the time of the new date-time, not null
* @return the date-time, not null
*/
private ChronoLocalDateTimeImpl<C> with(Temporal newDate, LocalTime newTime) {
private ChronoLocalDateTimeImpl<D> with(Temporal newDate, LocalTime newTime) {
if (date == newDate && time == newTime) {
return this;
}
// Validate that the new Temporal is a ChronoLocalDate (and not something else)
ChronoLocalDate<C> cd = date.getChrono().ensureChronoLocalDate(newDate);
return new ChronoLocalDateTimeImpl<>(cd, newTime);
D cd = (D)date.getChronology().ensureChronoLocalDate(newDate);
return new ChronoLocalDateTimeImpl<>((D)cd, newTime);
}
//-----------------------------------------------------------------------
@Override
public ChronoLocalDate<C> getDate() {
public D toLocalDate() {
return date;
}
@Override
public LocalTime getTime() {
public LocalTime toLocalTime() {
return time;
}
@ -216,7 +223,7 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
ChronoField f = (ChronoField) field;
return f.isDateField() || f.isTimeField();
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
@Override
@ -225,7 +232,7 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
ChronoField f = (ChronoField) field;
return (f.isTimeField() ? time.range(field) : date.range(field));
}
return field.doRange(this);
return field.rangeRefinedBy(this);
}
@Override
@ -243,26 +250,26 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
ChronoField f = (ChronoField) field;
return (f.isTimeField() ? time.getLong(field) : date.getLong(field));
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
@SuppressWarnings("unchecked")
@Override
public ChronoLocalDateTimeImpl<C> with(TemporalAdjuster adjuster) {
public ChronoLocalDateTimeImpl<D> with(TemporalAdjuster adjuster) {
if (adjuster instanceof ChronoLocalDate) {
// The Chrono is checked in with(date,time)
return with((ChronoLocalDate<C>) adjuster, time);
// The Chronology is checked in with(date,time)
return with((ChronoLocalDate<D>) adjuster, time);
} else if (adjuster instanceof LocalTime) {
return with(date, (LocalTime) adjuster);
} else if (adjuster instanceof ChronoLocalDateTimeImpl) {
return date.getChrono().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster);
return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster));
}
return date.getChrono().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster.adjustInto(this));
return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster.adjustInto(this)));
}
@Override
public ChronoLocalDateTimeImpl<C> with(TemporalField field, long newValue) {
public ChronoLocalDateTimeImpl<D> with(TemporalField field, long newValue) {
if (field instanceof ChronoField) {
ChronoField f = (ChronoField) field;
if (f.isTimeField()) {
@ -271,12 +278,12 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
return with(date.with(field, newValue), time);
}
}
return date.getChrono().ensureChronoLocalDateTime(field.doWith(this, newValue));
return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime(field.adjustInto(this, newValue)));
}
//-----------------------------------------------------------------------
@Override
public ChronoLocalDateTimeImpl<C> plus(long amountToAdd, TemporalUnit unit) {
public ChronoLocalDateTimeImpl<D> plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
ChronoUnit f = (ChronoUnit) unit;
switch (f) {
@ -290,31 +297,31 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
}
return with(date.plus(amountToAdd, unit), time);
}
return date.getChrono().ensureChronoLocalDateTime(unit.doPlus(this, amountToAdd));
return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime(unit.addTo(this, amountToAdd)));
}
private ChronoLocalDateTimeImpl<C> plusDays(long days) {
private ChronoLocalDateTimeImpl<D> plusDays(long days) {
return with(date.plus(days, ChronoUnit.DAYS), time);
}
private ChronoLocalDateTimeImpl<C> plusHours(long hours) {
private ChronoLocalDateTimeImpl<D> plusHours(long hours) {
return plusWithOverflow(date, hours, 0, 0, 0);
}
private ChronoLocalDateTimeImpl<C> plusMinutes(long minutes) {
private ChronoLocalDateTimeImpl<D> plusMinutes(long minutes) {
return plusWithOverflow(date, 0, minutes, 0, 0);
}
ChronoLocalDateTimeImpl<C> plusSeconds(long seconds) {
ChronoLocalDateTimeImpl<D> plusSeconds(long seconds) {
return plusWithOverflow(date, 0, 0, seconds, 0);
}
private ChronoLocalDateTimeImpl<C> plusNanos(long nanos) {
private ChronoLocalDateTimeImpl<D> plusNanos(long nanos) {
return plusWithOverflow(date, 0, 0, 0, nanos);
}
//-----------------------------------------------------------------------
private ChronoLocalDateTimeImpl<C> plusWithOverflow(ChronoLocalDate<C> newDate, long hours, long minutes, long seconds, long nanos) {
private ChronoLocalDateTimeImpl<D> plusWithOverflow(ChronoLocalDate<?> newDate, long hours, long minutes, long seconds, long nanos) {
// 9223372036854775808 long, 2147483648 int
if ((hours | minutes | seconds | nanos) == 0) {
return with(newDate, time);
@ -337,7 +344,7 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
//-----------------------------------------------------------------------
@Override
public ChronoZonedDateTime<C> atZone(ZoneId zone) {
public ChronoZonedDateTime<D> atZone(ZoneId zone) {
return ChronoZonedDateTimeImpl.ofBest(this, zone, null);
}
@ -348,8 +355,8 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
throw new DateTimeException("Unable to calculate period between objects of two different types");
}
@SuppressWarnings("unchecked")
ChronoLocalDateTime<C> end = (ChronoLocalDateTime<C>) endDateTime;
if (getDate().getChrono().equals(end.getDate().getChrono()) == false) {
ChronoLocalDateTime<D> end = (ChronoLocalDateTime<D>) endDateTime;
if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
throw new DateTimeException("Unable to calculate period between two different chronologies");
}
if (unit instanceof ChronoUnit) {
@ -365,15 +372,15 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
}
return Math.addExact(amount, time.periodUntil(end.getTime(), unit));
return Math.addExact(amount, time.periodUntil(end.toLocalTime(), unit));
}
ChronoLocalDate<C> endDate = end.getDate();
if (end.getTime().isBefore(time)) {
endDate = endDate.minus(1, ChronoUnit.DAYS);
D endDate = end.toLocalDate();
if (end.toLocalTime().isBefore(time)) {
endDate = (D)endDate.minus(1, ChronoUnit.DAYS);
}
return date.periodUntil(endDate, unit);
}
return unit.between(this, endDateTime).getAmount();
return unit.between(this, endDateTime);
}
//-----------------------------------------------------------------------
@ -396,7 +403,7 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
}
static ChronoLocalDateTime<?> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
ChronoLocalDate<?> date = (ChronoLocalDate<?>) in.readObject();
ChronoLocalDate date = (ChronoLocalDate) in.readObject();
LocalTime time = (LocalTime) in.readObject();
return date.atTime(time);
}
@ -415,12 +422,12 @@ final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
@Override
public int hashCode() {
return getDate().hashCode() ^ getTime().hashCode();
return toLocalDate().hashCode() ^ toLocalTime().hashCode();
}
@Override
public String toString() {
return getDate().toString() + 'T' + getTime().toString();
return toLocalDate().toString() + 'T' + toLocalTime().toString();
}
}

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time.chrono;
import static java.time.temporal.ChronoField.INSTANT_SECONDS;
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
@ -72,6 +72,16 @@ import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
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.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.util.Comparator;
import java.util.Objects;
@ -83,7 +93,7 @@ import java.util.Objects;
* as {@link ZonedDateTime}, not this interface.</b>
* <p>
* A {@code ChronoZonedDateTime} is the abstract representation of an offset date-time
* where the {@code Chrono chronology}, or calendar system, is pluggable.
* where the {@code Chronology chronology}, or calendar system, is pluggable.
* The date-time is defined in terms of fields expressed by {@link TemporalField},
* where most common implementations are defined in {@link ChronoField}.
* The chronology defines how the calendar system operates and the meaning of
@ -102,10 +112,10 @@ import java.util.Objects;
* All implementations that can be instantiated must be final, immutable and thread-safe.
* Subclasses should be Serializable wherever possible.
*
* @param <C> the chronology of this date-time
* @param <D> the concrete type for the date of this date-time
* @since 1.8
*/
public interface ChronoZonedDateTime<C extends Chrono<C>>
public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>>
extends Temporal, Comparable<ChronoZonedDateTime<?>> {
/**
@ -125,7 +135,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
public int compare(ChronoZonedDateTime<?> datetime1, ChronoZonedDateTime<?> datetime2) {
int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond());
if (cmp == 0) {
cmp = Long.compare(datetime1.getTime().toNanoOfDay(), datetime2.getTime().toNanoOfDay());
cmp = Long.compare(datetime1.toLocalTime().toNanoOfDay(), datetime2.toLocalTime().toNanoOfDay());
}
return cmp;
}
@ -137,9 +147,9 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {
return field.range();
}
return getDateTime().range(field);
return toLocalDateTime().range(field);
}
return field.doRange(this);
return field.rangeRefinedBy(this);
}
@Override
@ -149,7 +159,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
case INSTANT_SECONDS: throw new DateTimeException("Field too large for an int: " + field);
case OFFSET_SECONDS: return getOffset().getTotalSeconds();
}
return getDateTime().get(field);
return toLocalDateTime().get(field);
}
return Temporal.super.get(field);
}
@ -161,9 +171,9 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
case INSTANT_SECONDS: return toEpochSecond();
case OFFSET_SECONDS: return getOffset().getTotalSeconds();
}
return getDateTime().getLong(field);
return toLocalDateTime().getLong(field);
}
return field.doGet(this);
return field.getFrom(this);
}
/**
@ -174,8 +184,8 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
*
* @return the date part of this date-time, not null
*/
public default ChronoLocalDate<C> getDate() {
return getDateTime().getDate();
public default D toLocalDate() {
return toLocalDateTime().toLocalDate();
}
/**
@ -186,8 +196,8 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
*
* @return the time part of this date-time, not null
*/
public default LocalTime getTime() {
return getDateTime().getTime();
public default LocalTime toLocalTime() {
return toLocalDateTime().toLocalTime();
}
/**
@ -198,7 +208,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
*
* @return the local date-time part of this date-time, not null
*/
ChronoLocalDateTime<C> getDateTime();
ChronoLocalDateTime<D> toLocalDateTime();
/**
* Gets the zone offset, such as '+01:00'.
@ -237,7 +247,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @throws DateTimeException if no rules can be found for the zone
* @throws DateTimeException if no rules are valid for this date-time
*/
ChronoZonedDateTime<C> withEarlierOffsetAtOverlap();
ChronoZonedDateTime<D> withEarlierOffsetAtOverlap();
/**
* Returns a copy of this date-time changing the zone offset to the
@ -257,7 +267,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @throws DateTimeException if no rules can be found for the zone
* @throws DateTimeException if no rules are valid for this date-time
*/
ChronoZonedDateTime<C> withLaterOffsetAtOverlap();
ChronoZonedDateTime<D> withLaterOffsetAtOverlap();
/**
* Returns a copy of this ZonedDateTime with a different time-zone,
@ -274,7 +284,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @param zone the time-zone to change to, not null
* @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null
*/
ChronoZonedDateTime<C> withZoneSameLocal(ZoneId zone);
ChronoZonedDateTime<D> withZoneSameLocal(ZoneId zone);
/**
* Returns a copy of this date-time with a different time-zone,
@ -293,7 +303,10 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
ChronoZonedDateTime<C> withZoneSameInstant(ZoneId zone);
ChronoZonedDateTime<D> withZoneSameInstant(ZoneId zone);
@Override // Override to provide javadoc
public boolean isSupported(TemporalField field);
//-----------------------------------------------------------------------
// override for covariant return type
@ -303,8 +316,8 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoZonedDateTime<C> with(TemporalAdjuster adjuster) {
return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.with(adjuster));
public default ChronoZonedDateTime<D> with(TemporalAdjuster adjuster) {
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.with(adjuster)));
}
/**
@ -313,7 +326,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
ChronoZonedDateTime<C> with(TemporalField field, long newValue);
ChronoZonedDateTime<D> with(TemporalField field, long newValue);
/**
* {@inheritDoc}
@ -321,8 +334,8 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoZonedDateTime<C> plus(TemporalAdder adder) {
return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.plus(adder));
public default ChronoZonedDateTime<D> plus(TemporalAmount amount) {
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.plus(amount)));
}
/**
@ -331,7 +344,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
ChronoZonedDateTime<C> plus(long amountToAdd, TemporalUnit unit);
ChronoZonedDateTime<D> plus(long amountToAdd, TemporalUnit unit);
/**
* {@inheritDoc}
@ -339,8 +352,8 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoZonedDateTime<C> minus(TemporalSubtractor subtractor) {
return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.minus(subtractor));
public default ChronoZonedDateTime<D> minus(TemporalAmount amount) {
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amount)));
}
/**
@ -349,8 +362,8 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public default ChronoZonedDateTime<C> minus(long amountToSubtract, TemporalUnit unit) {
return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.minus(amountToSubtract, unit));
public default ChronoZonedDateTime<D> minus(long amountToSubtract, TemporalUnit unit) {
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amountToSubtract, unit)));
}
//-----------------------------------------------------------------------
@ -377,14 +390,17 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
public default <R> R query(TemporalQuery<R> query) {
if (query == Queries.zone() || query == Queries.zoneId()) {
return (R) getZone();
} else if (query == Queries.chrono()) {
return (R) getDate().getChrono();
} else if (query == Queries.precision()) {
return (R) NANOS;
} else if (query == Queries.offset()) {
return (R) getOffset();
} else if (query == Queries.localTime()) {
return (R) toLocalTime();
} else if (query == Queries.chronology()) {
return (R) toLocalDate().getChronology();
} else if (query == Queries.precision()) {
return (R) NANOS;
}
// inline TemporalAccessor.super.query(query) as an optimization
// non-JDK classes are not permitted to make this optimization
return query.queryFrom(this);
}
@ -392,20 +408,22 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
/**
* Converts this date-time to an {@code Instant}.
* <p>
* This combines the {@linkplain #getDateTime() local date-time} and
* {@linkplain #getOffset() offset} to form an {@code Instant}.
* This returns an {@code Instant} representing the same point on the
* time-line as this date-time. The calculation combines the
* {@linkplain #toLocalDateTime() local date-time} and
* {@linkplain #getOffset() offset}.
*
* @return an {@code Instant} representing the same instant, not null
*/
public default Instant toInstant() {
return Instant.ofEpochSecond(toEpochSecond(), getTime().getNano());
return Instant.ofEpochSecond(toEpochSecond(), toLocalTime().getNano());
}
/**
* Converts this date-time to the number of seconds from the epoch
* of 1970-01-01T00:00:00Z.
* <p>
* This uses the {@linkplain #getDateTime() local date-time} and
* This uses the {@linkplain #toLocalDateTime() local date-time} and
* {@linkplain #getOffset() offset} to calculate the epoch-second value,
* which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
* Instants on the time-line after the epoch are positive, earlier are negative.
@ -413,8 +431,8 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
*/
public default long toEpochSecond() {
long epochDay = getDate().toEpochDay();
long secs = epochDay * 86400 + getTime().toSecondOfDay();
long epochDay = toLocalDate().toEpochDay();
long secs = epochDay * 86400 + toLocalTime().toSecondOfDay();
secs -= getOffset().getTotalSeconds();
return secs;
}
@ -439,13 +457,13 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
public default int compareTo(ChronoZonedDateTime<?> other) {
int cmp = Long.compare(toEpochSecond(), other.toEpochSecond());
if (cmp == 0) {
cmp = getTime().getNano() - other.getTime().getNano();
cmp = toLocalTime().getNano() - other.toLocalTime().getNano();
if (cmp == 0) {
cmp = getDateTime().compareTo(other.getDateTime());
cmp = toLocalDateTime().compareTo(other.toLocalDateTime());
if (cmp == 0) {
cmp = getZone().getId().compareTo(other.getZone().getId());
if (cmp == 0) {
cmp = getDate().getChrono().compareTo(other.getDate().getChrono());
cmp = toLocalDate().getChronology().compareTo(other.toLocalDate().getChronology());
}
}
}
@ -470,7 +488,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
long thisEpochSec = toEpochSecond();
long otherEpochSec = other.toEpochSecond();
return thisEpochSec < otherEpochSec ||
(thisEpochSec == otherEpochSec && getTime().getNano() < other.getTime().getNano());
(thisEpochSec == otherEpochSec && toLocalTime().getNano() < other.toLocalTime().getNano());
}
/**
@ -490,7 +508,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
long thisEpochSec = toEpochSecond();
long otherEpochSec = other.toEpochSecond();
return thisEpochSec > otherEpochSec ||
(thisEpochSec == otherEpochSec && getTime().getNano() > other.getTime().getNano());
(thisEpochSec == otherEpochSec && toLocalTime().getNano() > other.toLocalTime().getNano());
}
/**
@ -508,7 +526,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
*/
public default boolean isEqual(ChronoZonedDateTime<?> other) {
return toEpochSecond() == other.toEpochSecond() &&
getTime().getNano() == other.getTime().getNano();
toLocalTime().getNano() == other.toLocalTime().getNano();
}
//-----------------------------------------------------------------------
@ -549,7 +567,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
* <p>
* The default implementation must behave as follows:
* <pre>
* return formatter.print(this);
* return formatter.format(this);
* </pre>
*
* @param formatter the formatter to use, not null
@ -558,7 +576,7 @@ public interface ChronoZonedDateTime<C extends Chrono<C>>
*/
public default String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.print(this);
return formatter.format(this);
}
}

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time.chrono;
import static java.time.temporal.ChronoUnit.SECONDS;
@ -74,6 +74,11 @@ import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.zone.ZoneOffsetTransition;
import java.time.zone.ZoneRules;
import java.util.List;
@ -93,11 +98,11 @@ import java.util.Objects;
* <h3>Specification for implementors</h3>
* This class is immutable and thread-safe.
*
* @param <C> the chronology of this date
* @param <D> the concrete type for the date of this date-time
* @since 1.8
*/
final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
implements ChronoZonedDateTime<C>, Serializable {
final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
implements ChronoZonedDateTime<D>, Serializable {
/**
* Serialization version.
@ -107,7 +112,7 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
/**
* The local date-time.
*/
private final ChronoLocalDateTimeImpl<C> dateTime;
private final ChronoLocalDateTimeImpl<D> dateTime;
/**
* The zone offset.
*/
@ -126,12 +131,12 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
* @param preferredOffset the zone offset, null if no preference
* @return the zoned date-time, not null
*/
static <R extends Chrono<R>> ChronoZonedDateTime<R> ofBest(
static <R extends ChronoLocalDate<R>> ChronoZonedDateTime<R> ofBest(
ChronoLocalDateTimeImpl<R> localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
Objects.requireNonNull(localDateTime, "localDateTime");
Objects.requireNonNull(zone, "zone");
if (zone instanceof ZoneOffset) {
return new ChronoZonedDateTimeImpl<R>(localDateTime, (ZoneOffset) zone, zone);
return new ChronoZonedDateTimeImpl<>(localDateTime, (ZoneOffset) zone, zone);
}
ZoneRules rules = zone.getRules();
LocalDateTime isoLDT = LocalDateTime.from(localDateTime);
@ -151,7 +156,7 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
}
}
Objects.requireNonNull(offset, "offset"); // protect against bad ZoneRules
return new ChronoZonedDateTimeImpl<R>(localDateTime, offset, zone);
return new ChronoZonedDateTimeImpl<>(localDateTime, offset, zone);
}
/**
@ -162,13 +167,13 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
* @param zone the zone identifier, not null
* @return the zoned date-time, not null
*/
static <R extends Chrono<R>> ChronoZonedDateTimeImpl<R> ofInstant(Chrono<R> chrono, Instant instant, ZoneId zone) {
static ChronoZonedDateTimeImpl<?> ofInstant(Chronology chrono, Instant instant, ZoneId zone) {
ZoneRules rules = zone.getRules();
ZoneOffset offset = rules.getOffset(instant);
Objects.requireNonNull(offset, "offset"); // protect against bad ZoneRules
LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
ChronoLocalDateTimeImpl<R> cldt = (ChronoLocalDateTimeImpl<R>) chrono.localDateTime(ldt);
return new ChronoZonedDateTimeImpl<R>(cldt, offset, zone);
ChronoLocalDateTimeImpl<?> cldt = (ChronoLocalDateTimeImpl<?>) chrono.localDateTime(ldt);
return new ChronoZonedDateTimeImpl(cldt, offset, zone);
}
/**
@ -178,8 +183,8 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
* @param zone the time-zone to use, validated not null
* @return the zoned date-time, validated not null
*/
private ChronoZonedDateTimeImpl<C> create(Instant instant, ZoneId zone) {
return ofInstant(getDate().getChrono(), instant, zone);
private ChronoZonedDateTimeImpl<D> create(Instant instant, ZoneId zone) {
return (ChronoZonedDateTimeImpl<D>)ofInstant(toLocalDate().getChronology(), instant, zone);
}
//-----------------------------------------------------------------------
@ -190,7 +195,7 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
* @param offset the zone offset, not null
* @param zone the zone ID, not null
*/
private ChronoZonedDateTimeImpl(ChronoLocalDateTimeImpl<C> dateTime, ZoneOffset offset, ZoneId zone) {
private ChronoZonedDateTimeImpl(ChronoLocalDateTimeImpl<D> dateTime, ZoneOffset offset, ZoneId zone) {
this.dateTime = Objects.requireNonNull(dateTime, "dateTime");
this.offset = Objects.requireNonNull(offset, "offset");
this.zone = Objects.requireNonNull(zone, "zone");
@ -202,24 +207,24 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
}
@Override
public ChronoZonedDateTime<C> withEarlierOffsetAtOverlap() {
public ChronoZonedDateTime<D> withEarlierOffsetAtOverlap() {
ZoneOffsetTransition trans = getZone().getRules().getTransition(LocalDateTime.from(this));
if (trans != null && trans.isOverlap()) {
ZoneOffset earlierOffset = trans.getOffsetBefore();
if (earlierOffset.equals(offset) == false) {
return new ChronoZonedDateTimeImpl<C>(dateTime, earlierOffset, zone);
return new ChronoZonedDateTimeImpl<D>(dateTime, earlierOffset, zone);
}
}
return this;
}
@Override
public ChronoZonedDateTime<C> withLaterOffsetAtOverlap() {
public ChronoZonedDateTime<D> withLaterOffsetAtOverlap() {
ZoneOffsetTransition trans = getZone().getRules().getTransition(LocalDateTime.from(this));
if (trans != null) {
ZoneOffset offset = trans.getOffsetAfter();
if (offset.equals(getOffset()) == false) {
return new ChronoZonedDateTimeImpl<C>(dateTime, offset, zone);
return new ChronoZonedDateTimeImpl<D>(dateTime, offset, zone);
}
}
return this;
@ -227,7 +232,7 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
//-----------------------------------------------------------------------
@Override
public ChronoLocalDateTime<C> getDateTime() {
public ChronoLocalDateTime<D> toLocalDateTime() {
return dateTime;
}
@ -235,12 +240,12 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
return zone;
}
public ChronoZonedDateTime<C> withZoneSameLocal(ZoneId zone) {
public ChronoZonedDateTime<D> withZoneSameLocal(ZoneId zone) {
return ofBest(dateTime, zone, offset);
}
@Override
public ChronoZonedDateTime<C> withZoneSameInstant(ZoneId zone) {
public ChronoZonedDateTime<D> withZoneSameInstant(ZoneId zone) {
Objects.requireNonNull(zone, "zone");
return this.zone.equals(zone) ? this : create(dateTime.toInstant(offset), zone);
}
@ -248,12 +253,12 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
//-----------------------------------------------------------------------
@Override
public boolean isSupported(TemporalField field) {
return field instanceof ChronoField || (field != null && field.doIsSupported(this));
return field instanceof ChronoField || (field != null && field.isSupportedBy(this));
}
//-----------------------------------------------------------------------
@Override
public ChronoZonedDateTime<C> with(TemporalField field, long newValue) {
public ChronoZonedDateTime<D> with(TemporalField field, long newValue) {
if (field instanceof ChronoField) {
ChronoField f = (ChronoField) field;
switch (f) {
@ -265,16 +270,16 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
}
return ofBest(dateTime.with(field, newValue), zone, offset);
}
return getDate().getChrono().ensureChronoZonedDateTime(field.doWith(this, newValue));
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(field.adjustInto(this, newValue)));
}
//-----------------------------------------------------------------------
@Override
public ChronoZonedDateTime<C> plus(long amountToAdd, TemporalUnit unit) {
public ChronoZonedDateTime<D> plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return with(dateTime.plus(amountToAdd, unit));
}
return getDate().getChrono().ensureChronoZonedDateTime(unit.doPlus(this, amountToAdd)); /// TODO: Generics replacement Risk!
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(unit.addTo(this, amountToAdd))); /// TODO: Generics replacement Risk!
}
//-----------------------------------------------------------------------
@ -284,15 +289,15 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
throw new DateTimeException("Unable to calculate period between objects of two different types");
}
@SuppressWarnings("unchecked")
ChronoZonedDateTime<C> end = (ChronoZonedDateTime<C>) endDateTime;
if (getDate().getChrono().equals(end.getDate().getChrono()) == false) {
ChronoZonedDateTime<D> end = (ChronoZonedDateTime<D>) endDateTime;
if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
throw new DateTimeException("Unable to calculate period between two different chronologies");
}
if (unit instanceof ChronoUnit) {
end = end.withZoneSameInstant(offset);
return dateTime.periodUntil(end.getDateTime(), unit);
return dateTime.periodUntil(end.toLocalDateTime(), unit);
}
return unit.between(this, endDateTime).getAmount();
return unit.between(this, endDateTime);
}
//-----------------------------------------------------------------------
@ -337,12 +342,12 @@ final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
@Override
public int hashCode() {
return getDateTime().hashCode() ^ getOffset().hashCode() ^ Integer.rotateLeft(getZone().hashCode(), 3);
return toLocalDateTime().hashCode() ^ getOffset().hashCode() ^ Integer.rotateLeft(getZone().hashCode(), 3);
}
@Override
public String toString() {
String str = getDateTime().toString() + getOffset().toString();
String str = toLocalDateTime().toString() + getOffset().toString();
if (getOffset() != getZone()) {
str += '[' + getZone().toString() + ']';
}

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time.chrono;
import java.io.DataInput;
import java.io.DataOutput;
@ -72,12 +72,19 @@ import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.calendar.HijrahChrono;
import java.time.calendar.JapaneseChrono;
import java.time.calendar.MinguoChrono;
import java.time.calendar.ThaiBuddhistChrono;
import java.time.chrono.HijrahChronology;
import java.time.chrono.JapaneseChronology;
import java.time.chrono.MinguoChronology;
import java.time.chrono.ThaiBuddhistChronology;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.ValueRange;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@ -95,30 +102,30 @@ import java.util.concurrent.ConcurrentHashMap;
* <p>
* Most other calendar systems also operate on the shared concepts of year, month and day,
* linked to the cycles of the Earth around the Sun, and the Moon around the Earth.
* These shared concepts are defined by {@link ChronoField} and are availalbe
* for use by any {@code Chrono} implementation:
* These shared concepts are defined by {@link ChronoField} and are available
* for use by any {@code Chronology} implementation:
* <pre>
* LocalDate isoDate = ...
* ChronoLocalDate&lt;ThaiBuddhistChrono&gt; thaiDate = ...
* ChronoLocalDate&lt;ThaiBuddhistChronology&gt; thaiDate = ...
* int isoYear = isoDate.get(ChronoField.YEAR);
* int thaiYear = thaiDate.get(ChronoField.YEAR);
* </pre>
* As shown, although the date objects are in different calendar systems, represented by different
* {@code Chrono} instances, both can be queried using the same constant on {@code ChronoField}.
* {@code Chronology} instances, both can be queried using the same constant on {@code ChronoField}.
* For a full discussion of the implications of this, see {@link ChronoLocalDate}.
* In general, the advice is to use the known ISO-based {@code LocalDate}, rather than
* {@code ChronoLocalDate}.
* <p>
* While a {@code Chrono} object typically uses {@code ChronoField} and is based on
* While a {@code Chronology} object typically uses {@code ChronoField} and is based on
* an era, year-of-era, month-of-year, day-of-month model of a date, this is not required.
* A {@code Chrono} instance may represent a totally different kind of calendar system,
* A {@code Chronology} instance may represent a totally different kind of calendar system,
* such as the Mayan.
* <p>
* In practical terms, the {@code Chrono} instance also acts as a factory.
* In practical terms, the {@code Chronology} instance also acts as a factory.
* The {@link #of(String)} method allows an instance to be looked up by identifier,
* while the {@link #ofLocale(Locale)} method allows lookup by locale.
* <p>
* The {@code Chrono} instance provides a set of methods to create {@code ChronoLocalDate} instances.
* The {@code Chronology} instance provides a set of methods to create {@code ChronoLocalDate} instances.
* The date classes are used to manipulate specific dates.
* <p><ul>
* <li> {@link #dateNow() dateNow()}
@ -131,16 +138,16 @@ import java.util.concurrent.ConcurrentHashMap;
* <li> {@link #date(TemporalAccessor) date(TemporalAccessor)}
* </ul><p>
*
* <p id="addcalendars">Adding New Calendars</p>
* <h3 id="addcalendars">Adding New Calendars</h3>
* The set of available chronologies can be extended by applications.
* Adding a new calendar system requires the writing of an implementation of
* {@code Chrono}, {@code ChronoLocalDate} and {@code Era}.
* {@code Chronology}, {@code ChronoLocalDate} and {@code Era}.
* The majority of the logic specific to the calendar system will be in
* {@code ChronoLocalDate}. The {@code Chrono} subclass acts as a factory.
* {@code ChronoLocalDate}. The {@code Chronology} subclass acts as a factory.
* <p>
* To permit the discovery of additional chronologies, the {@link java.util.ServiceLoader ServiceLoader}
* is used. A file must be added to the {@code META-INF/services} directory with the
* name 'java.time.temporal.Chrono' listing the implementation classes.
* name 'java.time.chrono.Chronology' listing the implementation classes.
* See the ServiceLoader for more details on service loading.
* For lookup by id or calendarType, the system provided calendars are found
* first followed by application provided calendars.
@ -155,28 +162,27 @@ import java.util.concurrent.ConcurrentHashMap;
* All implementations that can be instantiated must be final, immutable and thread-safe.
* Subclasses should be Serializable wherever possible.
*
* @param <C> the type of the implementing subclass
* @since 1.8
*/
public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?>> {
public abstract class Chronology implements Comparable<Chronology> {
/**
* Map of available calendars by ID.
*/
private static final ConcurrentHashMap<String, Chrono<?>> CHRONOS_BY_ID = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, Chronology> CHRONOS_BY_ID = new ConcurrentHashMap<>();
/**
* Map of available calendars by calendar type.
*/
private static final ConcurrentHashMap<String, Chrono<?>> CHRONOS_BY_TYPE = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, Chronology> CHRONOS_BY_TYPE = new ConcurrentHashMap<>();
/**
* Register a Chrono by ID and type for lookup by {@link #of(java.lang.String)}.
* Register a Chronology by ID and type for lookup by {@link #of(java.lang.String)}.
* Chronos must not be registered until they are completely constructed.
* Specifically, not in the constructor of Chrono.
* Specifically, not in the constructor of Chronology.
* @param chrono the chronology to register; not null
*/
private static void registerChrono(Chrono chrono) {
Chrono<?> prev = CHRONOS_BY_ID.putIfAbsent(chrono.getId(), chrono);
private static void registerChrono(Chronology chrono) {
Chronology prev = CHRONOS_BY_ID.putIfAbsent(chrono.getId(), chrono);
if (prev == null) {
String type = chrono.getCalendarType();
if (type != null) {
@ -186,17 +192,17 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
}
/**
* Initialization of the maps from id and type to Chrono.
* Initialization of the maps from id and type to Chronology.
* The ServiceLoader is used to find and register any implementations
* of {@link javax.time.temporal.Chrono} found in the bootclass loader.
* of {@link java.time.chrono.Chronology} found in the bootclass loader.
* The built-in chronologies are registered explicitly.
* Calendars configured via the Thread's context classloader are local
* to that thread and are ignored.
* <p>
* The initialization is done only once using the registration
* of the ISOChrono as the test and the final step.
* of the IsoChronology as the test and the final step.
* Multiple threads may perform the initialization concurrently.
* Only the first registration of each Chrono is retained by the
* Only the first registration of each Chronology is retained by the
* ConcurrentHashMap.
* @return true if the cache was initialized
*/
@ -204,19 +210,19 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
if (CHRONOS_BY_ID.get("ISO") == null) {
// Initialization is incomplete
@SuppressWarnings("rawtypes")
ServiceLoader<Chrono> loader = ServiceLoader.load(Chrono.class, null);
for (Chrono<?> chrono : loader) {
ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class, null);
for (Chronology chrono : loader) {
registerChrono(chrono);
}
// Register these calendars; the ServiceLoader configuration is not used
registerChrono(HijrahChrono.INSTANCE);
registerChrono(JapaneseChrono.INSTANCE);
registerChrono(MinguoChrono.INSTANCE);
registerChrono(ThaiBuddhistChrono.INSTANCE);
registerChrono(HijrahChronology.INSTANCE);
registerChrono(JapaneseChronology.INSTANCE);
registerChrono(MinguoChronology.INSTANCE);
registerChrono(ThaiBuddhistChronology.INSTANCE);
// finally, register ISOChrono to mark initialization is complete
registerChrono(ISOChrono.INSTANCE);
// finally, register IsoChronology to mark initialization is complete
registerChrono(IsoChronology.INSTANCE);
return true;
}
return false;
@ -224,61 +230,89 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Chrono} from a temporal object.
* Obtains an instance of {@code Chronology} from a temporal object.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code Chrono}.
* If the specified temporal object does not have a chronology, {@link ISOChrono} is returned.
* This obtains a chronology 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 Chronology}.
* <p>
* The conversion will obtain the chronology using {@link Queries#chrono()}.
* The conversion will obtain the chronology using {@link Queries#chronology()}.
* If the specified temporal object does not have a chronology, {@link IsoChronology} is returned.
* <p>
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used in queries via method reference, {@code Chrono::from}.
* allowing it to be used in queries via method reference, {@code Chronology::from}.
*
* @param temporal the temporal to convert, not null
* @return the chronology, not null
* @throws DateTimeException if unable to convert to an {@code Chrono}
* @throws DateTimeException if unable to convert to an {@code Chronology}
*/
public static Chrono<?> from(TemporalAccessor temporal) {
public static Chronology from(TemporalAccessor temporal) {
Objects.requireNonNull(temporal, "temporal");
Chrono<?> obj = temporal.query(Queries.chrono());
return (obj != null ? obj : ISOChrono.INSTANCE);
Chronology obj = temporal.query(Queries.chronology());
return (obj != null ? obj : IsoChronology.INSTANCE);
}
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Chrono} from a locale.
* Obtains an instance of {@code Chronology} from a locale.
* <p>
* The locale can be used to identify a calendar.
* This uses {@link Locale#getUnicodeLocaleType(String)} to obtain the "ca" key
* to identify the calendar system.
* This returns a {@code Chronology} based on the specified locale,
* typically returning {@code IsoChronology}. Other calendar systems
* are only returned if they are explicitly selected within the locale.
* <p>
* If the locale does not contain calendar system information, the standard
* ISO calendar system is used.
* The {@link Locale} class provide access to a range of information useful
* for localizing an application. This includes the language and region,
* such as "en-GB" for English as used in Great Britain.
* <p>
* The {@code Locale} class also supports an extension mechanism that
* can be used to identify a calendar system. The mechanism is a form
* of key-value pairs, where the calendar system has the key "ca".
* For example, the locale "en-JP-u-ca-japanese" represents the English
* language as used in Japan with the Japanese calendar system.
* <p>
* This method finds the desired calendar system by in a manner equivalent
* to passing "ca" to {@link Locale#getUnicodeLocaleType(String)}.
* If the "ca" key is not present, then {@code IsoChronology} is returned.
* <p>
* Note that the behavior of this method differs from the older
* {@link java.util.Calendar#getInstance(Locale)} method.
* If that method receives a locale of "th_TH" it will return {@code BuddhistCalendar}.
* By contrast, this method will return {@code IsoChronology}.
* Passing the locale "th-TH-u-ca-buddhist" into either method will
* result in the Thai Buddhist calendar system and is therefore the
* recommended approach going forward for Thai calendar system localization.
* <p>
* A similar, but simpler, situation occurs for the Japanese calendar system.
* The locale "jp_JP_JP" has previously been used to access the calendar.
* However, unlike the Thai locale, "ja_JP_JP" is automatically converted by
* {@code Locale} to the modern and recommended form of "ja-JP-u-ca-japanese".
* Thus, there is no difference in behavior between this method and
* {@code Calendar#getInstance(Locale)}.
*
* @param locale the locale to use to obtain the calendar system, not null
* @return the calendar system associated with the locale, not null
* @throws DateTimeException if the locale-specified calendar cannot be found
*/
public static Chrono<?> ofLocale(Locale locale) {
public static Chronology ofLocale(Locale locale) {
Objects.requireNonNull(locale, "locale");
String type = locale.getUnicodeLocaleType("ca");
if (type == null) {
return ISOChrono.INSTANCE;
} else if ("iso".equals(type) || "iso8601".equals(type)) {
return ISOChrono.INSTANCE;
} else {
Chrono<?> chrono = CHRONOS_BY_TYPE.get(type);
if (chrono == null) {
throw new DateTimeException("Unknown calendar system: " + type);
}
return chrono;
if (type == null || "iso".equals(type) || "iso8601".equals(type)) {
return IsoChronology.INSTANCE;
}
// Not pre-defined; lookup by the type
do {
Chronology chrono = CHRONOS_BY_TYPE.get(type);
if (chrono != null) {
return chrono;
}
// If not found, do the initialization (once) and repeat the lookup
} while (initCache());
throw new DateTimeException("Unknown calendar system: " + type);
}
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Chrono} from a chronology ID or
* Obtains an instance of {@code Chronology} from a chronology ID or
* calendar system type.
* <p>
* This returns a chronology based on either the ID or the type.
@ -296,21 +330,21 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the chronology with the identifier requested, not null
* @throws DateTimeException if the chronology cannot be found
*/
public static Chrono<?> of(String id) {
public static Chronology of(String id) {
Objects.requireNonNull(id, "id");
do {
Chrono chrono = of0(id);
Chronology chrono = of0(id);
if (chrono != null) {
return chrono;
}
// If not found, do the initialization (once) and repeat the lookup
} while (initCache());
// Look for a Chrono using ServiceLoader of the Thread's ContextClassLoader
// Look for a Chronology using ServiceLoader of the Thread's ContextClassLoader
// Application provided Chronologies must not be cached
@SuppressWarnings("rawtypes")
ServiceLoader<Chrono> loader = ServiceLoader.load(Chrono.class);
for (Chrono<?> chrono : loader) {
ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class);
for (Chronology chrono : loader) {
if (id.equals(chrono.getId()) || id.equals(chrono.getCalendarType())) {
return chrono;
}
@ -319,14 +353,14 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
}
/**
* Obtains an instance of {@code Chrono} from a chronology ID or
* Obtains an instance of {@code Chronology} from a chronology ID or
* calendar system type.
*
* @param id the chronology ID or calendar system type, not null
* @return the chronology with the identifier requested, or {@code null} if not found
*/
private static Chrono<?> of0(String id) {
Chrono<?> chrono = CHRONOS_BY_ID.get(id);
private static Chronology of0(String id) {
Chronology chrono = CHRONOS_BY_ID.get(id);
if (chrono == null) {
chrono = CHRONOS_BY_TYPE.get(id);
}
@ -336,50 +370,31 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
/**
* Returns the available chronologies.
* <p>
* Each returned {@code Chrono} is available for use in the system.
* Each returned {@code Chronology} is available for use in the system.
* The set of chronologies includes the system chronologies and
* any chronologies provided by the application via ServiceLoader
* configuration.
*
* @return the independent, modifiable set of the available chronology IDs, not null
*/
public static Set<Chrono<?>> getAvailableChronologies() {
public static Set<Chronology> getAvailableChronologies() {
initCache(); // force initialization
HashSet<Chrono<?>> chronos = new HashSet<>(CHRONOS_BY_ID.values());
HashSet<Chronology> chronos = new HashSet(CHRONOS_BY_ID.values());
/// Add in Chronologies from the ServiceLoader configuration
@SuppressWarnings("rawtypes")
ServiceLoader<Chrono> loader = ServiceLoader.load(Chrono.class);
for (Chrono<?> chrono : loader) {
ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class);
for (Chronology chrono : loader) {
chronos.add(chrono);
}
return chronos;
}
//-----------------------------------------------------------------------
/**
* Obtains a local date-time from the a date and time.
* <p>
* This combines a {@link ChronoLocalDate}, which provides the {@code Chrono},
* with a {@link LocalTime} to produce a {@link ChronoLocalDateTime}.
* <p>
* This method is intended for chronology implementations.
* It uses a standard implementation that is shared for all chronologies.
*
* @param <R> the chronology of the date
* @param date the date, not null
* @param time the time, not null
* @return the local date-time combining the input date and time, not null
*/
public static <R extends Chrono<R>> ChronoLocalDateTime<R> dateTime(ChronoLocalDate<R> date, LocalTime time) {
return ChronoLocalDateTimeImpl.of(date, time);
}
//-----------------------------------------------------------------------
/**
* Creates an instance.
*/
protected Chrono() {
protected Chronology() {
}
//-----------------------------------------------------------------------
@ -389,13 +404,13 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @param temporal a date-time to cast, not null
* @return the date-time checked and cast to {@code ChronoLocalDate}, not null
* @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate
* or the chronology is not equal this Chrono
* or the chronology is not equal this Chronology
*/
ChronoLocalDate<C> ensureChronoLocalDate(Temporal temporal) {
ChronoLocalDate ensureChronoLocalDate(Temporal temporal) {
@SuppressWarnings("unchecked")
ChronoLocalDate<C> other = (ChronoLocalDate<C>) temporal;
if (this.equals(other.getChrono()) == false) {
throw new ClassCastException("Chrono mismatch, expected: " + getId() + ", actual: " + other.getChrono().getId());
ChronoLocalDate other = (ChronoLocalDate) temporal;
if (this.equals(other.getChronology()) == false) {
throw new ClassCastException("Chronology mismatch, expected: " + getId() + ", actual: " + other.getChronology().getId());
}
return other;
}
@ -406,14 +421,14 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @param temporal a date-time to cast, not null
* @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null
* @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl
* or the chronology is not equal this Chrono
* or the chronology is not equal this Chronology
*/
ChronoLocalDateTimeImpl<C> ensureChronoLocalDateTime(Temporal temporal) {
ChronoLocalDateTimeImpl<?> ensureChronoLocalDateTime(Temporal temporal) {
@SuppressWarnings("unchecked")
ChronoLocalDateTimeImpl<C> other = (ChronoLocalDateTimeImpl<C>) temporal;
if (this.equals(other.getDate().getChrono()) == false) {
throw new ClassCastException("Chrono mismatch, required: " + getId()
+ ", supplied: " + other.getDate().getChrono().getId());
ChronoLocalDateTimeImpl<?> other = (ChronoLocalDateTimeImpl<?>) temporal;
if (this.equals(other.toLocalDate().getChronology()) == false) {
throw new ClassCastException("Chronology mismatch, required: " + getId()
+ ", supplied: " + other.toLocalDate().getChronology().getId());
}
return other;
}
@ -424,14 +439,14 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @param temporal a date-time to cast, not null
* @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null
* @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl
* or the chronology is not equal this Chrono
* or the chronology is not equal this Chronology
*/
ChronoZonedDateTimeImpl<C> ensureChronoZonedDateTime(Temporal temporal) {
ChronoZonedDateTimeImpl<?> ensureChronoZonedDateTime(Temporal temporal) {
@SuppressWarnings("unchecked")
ChronoZonedDateTimeImpl<C> other = (ChronoZonedDateTimeImpl<C>) temporal;
if (this.equals(other.getDate().getChrono()) == false) {
throw new ClassCastException("Chrono mismatch, required: " + getId()
+ ", supplied: " + other.getDate().getChrono().getId());
ChronoZonedDateTimeImpl<?> other = (ChronoZonedDateTimeImpl<?>) temporal;
if (this.equals(other.toLocalDate().getChronology()) == false) {
throw new ClassCastException("Chronology mismatch, required: " + getId()
+ ", supplied: " + other.toLocalDate().getChronology().getId());
}
return other;
}
@ -440,8 +455,8 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
/**
* Gets the ID of the chronology.
* <p>
* The ID uniquely identifies the {@code Chrono}.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* The ID uniquely identifies the {@code Chronology}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
*
* @return the chronology ID, not null
* @see #getCalendarType()
@ -453,7 +468,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* <p>
* The calendar type is an identifier defined by the
* <em>Unicode Locale Data Markup Language (LDML)</em> specification.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
* It can also be used as part of a locale, accessible via
* {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
*
@ -474,7 +489,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the local date in this chronology, not null
* @throws DateTimeException if unable to create the date
*/
public ChronoLocalDate<C> date(Era<C> era, int yearOfEra, int month, int dayOfMonth) {
public ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
}
@ -488,7 +503,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the local date in this chronology, not null
* @throws DateTimeException if unable to create the date
*/
public abstract ChronoLocalDate<C> date(int prolepticYear, int month, int dayOfMonth);
public abstract ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth);
/**
* Obtains a local date in this chronology from the era, year-of-era and
@ -500,7 +515,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the local date in this chronology, not null
* @throws DateTimeException if unable to create the date
*/
public ChronoLocalDate<C> dateYearDay(Era<C> era, int yearOfEra, int dayOfYear) {
public ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
}
@ -513,21 +528,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the local date in this chronology, not null
* @throws DateTimeException if unable to create the date
*/
public abstract ChronoLocalDate<C> dateYearDay(int prolepticYear, int dayOfYear);
/**
* Obtains a local date in this chronology from another temporal object.
* <p>
* This creates a date in this chronology based on the specified {@code TemporalAccessor}.
* <p>
* The standard mechanism for conversion between date types is the
* {@link ChronoField#EPOCH_DAY local epoch-day} field.
*
* @param temporal the temporal object to convert, not null
* @return the local date in this chronology, not null
* @throws DateTimeException if unable to create the date
*/
public abstract ChronoLocalDate<C> date(TemporalAccessor temporal);
public abstract ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear);
//-----------------------------------------------------------------------
/**
@ -544,7 +545,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the current local date using the system clock and default time-zone, not null
* @throws DateTimeException if unable to create the date
*/
public ChronoLocalDate<C> dateNow() {
public ChronoLocalDate dateNow() {
return dateNow(Clock.systemDefaultZone());
}
@ -561,7 +562,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the current local date using the system clock, not null
* @throws DateTimeException if unable to create the date
*/
public ChronoLocalDate<C> dateNow(ZoneId zone) {
public ChronoLocalDate dateNow(ZoneId zone) {
return dateNow(Clock.system(zone));
}
@ -576,27 +577,52 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the current local date, not null
* @throws DateTimeException if unable to create the date
*/
public ChronoLocalDate<C> dateNow(Clock clock) {
public ChronoLocalDate dateNow(Clock clock) {
Objects.requireNonNull(clock, "clock");
return date(LocalDate.now(clock));
}
//-----------------------------------------------------------------------
/**
* Obtains a local date in this chronology from another temporal object.
* <p>
* This creates a date in this chronology 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 ChronoLocalDate}.
* <p>
* The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
* field, which is standardized across calendar systems.
* <p>
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used as a query via method reference, {@code aChronology::date}.
*
* @param temporal the temporal object to convert, not null
* @return the local date in this chronology, not null
* @throws DateTimeException if unable to create the date
*/
public abstract ChronoLocalDate date(TemporalAccessor temporal);
/**
* Obtains a local date-time in this chronology from another temporal object.
* <p>
* This creates a date-time in this chronology based on the specified {@code TemporalAccessor}.
* This creates a date-time in this chronology 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 ChronoLocalDateTime}.
* <p>
* The date of the date-time should be equivalent to that obtained by calling
* {@link #date(TemporalAccessor)}.
* The standard mechanism for conversion between time types is the
* {@link ChronoField#NANO_OF_DAY nano-of-day} field.
* The conversion extracts and combines the {@code ChronoLocalDate} 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.
* The result uses this chronology.
* <p>
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used as a query via method reference, {@code aChronology::localDateTime}.
*
* @param temporal the temporal object to convert, not null
* @return the local date-time in this chronology, not null
* @throws DateTimeException if unable to create the date-time
*/
public ChronoLocalDateTime<C> localDateTime(TemporalAccessor temporal) {
public ChronoLocalDateTime<?> localDateTime(TemporalAccessor temporal) {
try {
return date(temporal).atTime(LocalTime.from(temporal));
} catch (DateTimeException ex) {
@ -605,19 +631,29 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
}
/**
* Obtains a zoned date-time in this chronology from another temporal object.
* Obtains a {@code ChronoZonedDateTime} in this chronology from another temporal object.
* <p>
* This creates a date-time in this chronology based on the specified {@code TemporalAccessor}.
* This creates a zoned date-time in this chronology 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 ChronoZonedDateTime}.
* <p>
* This should obtain a {@code ZoneId} using {@link ZoneId#from(TemporalAccessor)}.
* The date-time should be obtained by obtaining an {@code Instant}.
* If that fails, the local date-time should be used.
* The conversion will first obtain a {@code ZoneId} from the temporal object,
* falling back to a {@code ZoneOffset} if necessary. It will then try to obtain
* an {@code Instant}, falling back to a {@code ChronoLocalDateTime} if necessary.
* The result will be either the combination of {@code ZoneId} or {@code ZoneOffset}
* with {@code Instant} or {@code ChronoLocalDateTime}.
* Implementations are permitted to perform optimizations such as accessing
* those fields that are equivalent to the relevant objects.
* The result uses this chronology.
* <p>
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used as a query via method reference, {@code aChronology::zonedDateTime}.
*
* @param temporal the temporal object to convert, not null
* @return the zoned date-time in this chronology, not null
* @throws DateTimeException if unable to create the date-time
*/
public ChronoZonedDateTime<C> zonedDateTime(TemporalAccessor temporal) {
public ChronoZonedDateTime<?> zonedDateTime(TemporalAccessor temporal) {
try {
ZoneId zone = ZoneId.from(temporal);
try {
@ -625,7 +661,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
return zonedDateTime(instant, zone);
} catch (DateTimeException ex1) {
ChronoLocalDateTimeImpl<C> cldt = ensureChronoLocalDateTime(localDateTime(temporal));
ChronoLocalDateTimeImpl cldt = ensureChronoLocalDateTime(localDateTime(temporal));
return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null);
}
} catch (DateTimeException ex) {
@ -634,7 +670,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
}
/**
* Obtains a zoned date-time in this chronology from an {@code Instant}.
* Obtains a {@code ChronoZonedDateTime} in this chronology from an {@code Instant}.
* <p>
* This creates a zoned date-time with the same instant as that specified.
*
@ -643,7 +679,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the zoned date-time, not null
* @throws DateTimeException if the result exceeds the supported range
*/
public ChronoZonedDateTime<C> zonedDateTime(Instant instant, ZoneId zone) {
public ChronoZonedDateTime<?> zonedDateTime(Instant instant, ZoneId zone) {
return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone);
}
@ -673,7 +709,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the proleptic-year
* @throws DateTimeException if unable to convert
*/
public abstract int prolepticYear(Era<C> era, int yearOfEra);
public abstract int prolepticYear(Era era, int yearOfEra);
/**
* Creates the chronology era object from the numeric value.
@ -694,7 +730,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the calendar system era, not null
* @throws DateTimeException if unable to create the era
*/
public abstract Era<C> eraOf(int eraValue);
public abstract Era eraOf(int eraValue);
/**
* Gets the list of eras for the chronology.
@ -705,7 +741,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
*
* @return the list of eras for the chronology, may be immutable, not null
*/
public abstract List<Era<C>> eras();
public abstract List<Era> eras();
//-----------------------------------------------------------------------
/**
@ -730,15 +766,16 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
/**
* Gets the textual representation of this chronology.
* <p>
* This returns the textual name used to identify the chronology.
* This returns the textual name used to identify the chronology,
* suitable for presentation to the user.
* The parameters control the style of the returned text and the locale.
*
* @param style the style of the text required, not null
* @param locale the locale to use, not null
* @return the text value of the chronology, not null
*/
public String getText(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendChronoText(style).toFormatter(locale).print(new TemporalAccessor() {
public String getDisplayName(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendChronologyText(style).toFormatter(locale).format(new TemporalAccessor() {
@Override
public boolean isSupported(TemporalField field) {
return false;
@ -750,8 +787,8 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.chrono()) {
return (R) Chrono.this;
if (query == Queries.chronology()) {
return (R) Chronology.this;
}
return TemporalAccessor.super.query(query);
}
@ -773,7 +810,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* @return the comparator value, negative if less, positive if greater
*/
@Override
public int compareTo(Chrono<?> other) {
public int compareTo(Chronology other) {
return getId().compareTo(other.getId());
}
@ -782,7 +819,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* <p>
* The comparison is based on the entire state of the object.
* <p>
* The default implementation checks the type and calls {@link #compareTo(Chrono)}.
* The default implementation checks the type and calls {@link #compareTo(Chronology)}.
*
* @param obj the object to check, null returns false
* @return true if this is equal to the other chronology
@ -792,8 +829,8 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
if (this == obj) {
return true;
}
if (obj instanceof Chrono) {
return compareTo((Chrono<?>) obj) == 0;
if (obj instanceof Chronology) {
return compareTo((Chronology) obj) == 0;
}
return false;
}
@ -827,7 +864,7 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
* Writes the object using a
* <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
* <pre>
* out.writeByte(7); // identifies this as a Chrono
* out.writeByte(7); // identifies this as a Chronology
* out.writeUTF(chronoId);
* </pre>
*
@ -850,9 +887,9 @@ public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?
out.writeUTF(getId());
}
static Chrono<?> readExternal(DataInput in) throws IOException {
static Chronology readExternal(DataInput in) throws IOException {
String id = in.readUTF();
return Chrono.of(id);
return Chronology.of(id);
}
}

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time.chrono;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoUnit.ERAS;
@ -67,6 +67,14 @@ import static java.time.temporal.ChronoUnit.ERAS;
import java.time.DateTimeException;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.ValueRange;
import java.util.Locale;
/**
@ -77,7 +85,7 @@ import java.util.Locale;
* of each leader.
* In all cases, the era is conceptually the largest division of the time-line.
* Each chronology defines the Era's that are known Eras and a
* {@link Chrono#eras Chrono.eras} to get the valid eras.
* {@link Chronology#eras Chronology.eras} to get the valid eras.
* <p>
* For example, the Thai Buddhist calendar system divides time into two eras,
* before and after a single date. By contrast, the Japanese calendar system
@ -90,10 +98,9 @@ import java.util.Locale;
* All implementations must be singletons - final, immutable and thread-safe.
* It is recommended to use an enum whenever possible.
*
* @param <C> the chronology of the era
* @since 1.8
*/
public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdjuster {
public interface Era extends TemporalAccessor, TemporalAdjuster {
/**
* Gets the numeric value associated with the era as defined by the chronology.
@ -116,12 +123,12 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
/**
* Gets the chronology of this era.
* <p>
* The {@code Chrono} represents the calendar system in use.
* The {@code Chronology} represents the calendar system in use.
* This always returns the standard form of the chronology.
*
* @return the chronology, not null
*/
C getChrono();
Chronology getChronology();
//-----------------------------------------------------------------------
/**
@ -129,18 +136,18 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
* <p>
* This era is combined with the given date fields to form a date.
* The year specified must be the year-of-era.
* Methods to create a date from the proleptic-year are on {@code Chrono}.
* Methods to create a date from the proleptic-year are on {@code Chronology}.
* This always uses the standard form of the chronology.
* <p>
* This default implementation invokes the factory method on {@link Chrono}.
* This default implementation invokes the factory method on {@link Chronology}.
*
* @param yearOfEra the calendar system year-of-era
* @param month the calendar system month-of-year
* @param day the calendar system day-of-month
* @return a local date based on this era and the specified year-of-era, month and day
*/
public default ChronoLocalDate<C> date(int yearOfEra, int month, int day) {
return getChrono().date(this, yearOfEra, month, day);
public default ChronoLocalDate date(int yearOfEra, int month, int day) {
return getChronology().date(this, yearOfEra, month, day);
}
@ -149,17 +156,17 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
* <p>
* This era is combined with the given date fields to form a date.
* The year specified must be the year-of-era.
* Methods to create a date from the proleptic-year are on {@code Chrono}.
* Methods to create a date from the proleptic-year are on {@code Chronology}.
* This always uses the standard form of the chronology.
* <p>
* This default implementation invokes the factory method on {@link Chrono}.
* This default implementation invokes the factory method on {@link Chronology}.
*
* @param yearOfEra the calendar system year-of-era
* @param dayOfYear the calendar system day-of-year
* @return a local date based on this era and the specified year-of-era and day-of-year
*/
public default ChronoLocalDate<C> dateYearDay(int yearOfEra, int dayOfYear) {
return getChrono().dateYearDay(this, yearOfEra, dayOfYear);
public default ChronoLocalDate dateYearDay(int yearOfEra, int dayOfYear) {
return getChronology().dateYearDay(this, yearOfEra, dayOfYear);
}
//-----------------------------------------------------------------------
@ -175,7 +182,7 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
* 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.
*
@ -187,7 +194,7 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
if (field instanceof ChronoField) {
return field == ERA;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
@ -203,7 +210,7 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
* 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.
*
@ -229,7 +236,7 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
* 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.
*
@ -258,7 +265,7 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
* 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.
*
@ -274,7 +281,7 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
@ -299,8 +306,8 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
@SuppressWarnings("unchecked")
@Override
public default <R> R query(TemporalQuery<R> query) {
if (query == Queries.chrono()) {
return (R) getChrono();
if (query == Queries.chronology()) {
return (R) getChronology();
} else if (query == Queries.precision()) {
return (R) ERAS;
}
@ -340,7 +347,8 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
/**
* Gets the textual representation of this era.
* <p>
* This returns the textual name used to identify the era.
* This returns the textual name used to identify the era,
* 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.
@ -351,8 +359,8 @@ public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdju
* @param locale the locale to use, not null
* @return the text value of the era, not null
*/
public default String getText(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this);
public default String getDisplayName(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).format(this);
}
// NOTE: methods to convert year-of-era/proleptic-year cannot be here as they may depend on month/day (Japanese)

View File

@ -55,18 +55,19 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import static java.time.temporal.ChronoField.EPOCH_DAY;
import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.temporal.Chrono;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.Era;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.ValueRange;
import java.util.Arrays;
@ -175,7 +176,7 @@ import java.util.Locale;
*
* @since 1.8
*/
public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializable {
public final class HijrahChronology extends Chronology implements Serializable {
/**
* The Hijrah Calendar id.
@ -191,11 +192,11 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
* The singleton instance for the era before the current one - Before Hijrah -
* which has the value 0.
*/
public static final Era<HijrahChrono> ERA_BEFORE_AH = HijrahEra.BEFORE_AH;
public static final Era ERA_BEFORE_AH = HijrahEra.BEFORE_AH;
/**
* The singleton instance for the current era - Hijrah - which has the value 1.
*/
public static final Era<HijrahChrono> ERA_AH = HijrahEra.AH;
public static final Era ERA_AH = HijrahEra.AH;
/**
* Serialization version.
*/
@ -419,7 +420,7 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
* Singleton instance of the Hijrah chronology.
* Must be initialized after the rest of the static initialization.
*/
public static final HijrahChrono INSTANCE;
public static final HijrahChronology INSTANCE;
/**
* Name data.
@ -439,10 +440,10 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
DEFAULT_CYCLE_YEARS = Arrays.copyOf(CYCLEYEAR_START_DATE, CYCLEYEAR_START_DATE.length);
INSTANCE = new HijrahChrono();
INSTANCE = new HijrahChronology();
String extraCalendars = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("java.time.calendar.HijrahCalendars"));
new sun.security.action.GetPropertyAction("java.time.chrono.HijrahCalendars"));
if (extraCalendars != null) {
try {
// Split on whitespace
@ -451,7 +452,7 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
if (!cal.isEmpty()) {
// Split on the delimiter between typeId "-" calendarType
String[] type = cal.split("-");
Chrono<?> cal2 = new HijrahChrono(type[0], type.length > 1 ? type[1] : type[0]);
Chronology cal2 = new HijrahChronology(type[0], type.length > 1 ? type[1] : type[0]);
}
}
} catch (Exception ex) {
@ -464,15 +465,15 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
/**
* Restricted constructor.
*/
private HijrahChrono() {
private HijrahChronology() {
this("Hijrah", "islamicc");
}
/**
* Constructor for name and type HijrahChrono.
* Constructor for name and type HijrahChronology.
* @param id the id of the calendar
* @param calendarType the calendar type
*/
private HijrahChrono(String id, String calendarType) {
private HijrahChronology(String id, String calendarType) {
this.typeId = id;
this.calendarType = calendarType;
@ -507,8 +508,8 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
/**
* Gets the ID of the chronology - 'Hijrah'.
* <p>
* The ID uniquely identifies the {@code Chrono}.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* The ID uniquely identifies the {@code Chronology}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
*
* @return the chronology ID - 'Hijrah'
* @see #getCalendarType()
@ -523,7 +524,7 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
* <p>
* The calendar type is an identifier defined by the
* <em>Unicode Locale Data Markup Language (LDML)</em> specification.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
* It can also be used as part of a locale, accessible via
* {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
*
@ -537,23 +538,64 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
//-----------------------------------------------------------------------
@Override
public ChronoLocalDate<HijrahChrono> date(int prolepticYear, int month, int dayOfMonth) {
public HijrahDate date(int prolepticYear, int month, int dayOfMonth) {
return HijrahDate.of(this, prolepticYear, month, dayOfMonth);
}
@Override
public ChronoLocalDate<HijrahChrono> dateYearDay(int prolepticYear, int dayOfYear) {
public HijrahDate dateYearDay(int prolepticYear, int dayOfYear) {
return HijrahDate.of(this, prolepticYear, 1, 1).plusDays(dayOfYear - 1); // TODO better
}
@Override
public ChronoLocalDate<HijrahChrono> date(TemporalAccessor temporal) {
public HijrahDate date(TemporalAccessor temporal) {
if (temporal instanceof HijrahDate) {
return (HijrahDate) temporal;
}
return HijrahDate.ofEpochDay(this, temporal.getLong(EPOCH_DAY));
}
@Override
public HijrahDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
}
@Override
public HijrahDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
}
@Override
public HijrahDate dateNow() {
return dateNow(Clock.systemDefaultZone());
}
@Override
public HijrahDate dateNow(ZoneId zone) {
return dateNow(Clock.system(zone));
}
@Override
public HijrahDate dateNow(Clock clock) {
return date(LocalDate.now(clock));
}
@Override
public ChronoLocalDateTime<HijrahDate> localDateTime(TemporalAccessor temporal) {
return (ChronoLocalDateTime<HijrahDate>)super.localDateTime(temporal);
}
@Override
public ChronoZonedDateTime<HijrahDate> zonedDateTime(TemporalAccessor temporal) {
return (ChronoZonedDateTime<HijrahDate>)super.zonedDateTime(temporal);
}
@Override
public ChronoZonedDateTime<HijrahDate> zonedDateTime(Instant instant, ZoneId zone) {
return (ChronoZonedDateTime<HijrahDate>)super.zonedDateTime(instant, zone);
}
//-----------------------------------------------------------------------
@Override
public boolean isLeapYear(long prolepticYear) {
@ -569,7 +611,7 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
}
@Override
public int prolepticYear(Era<HijrahChrono> era, int yearOfEra) {
public int prolepticYear(Era era, int yearOfEra) {
if (era instanceof HijrahEra == false) {
throw new DateTimeException("Era must be HijrahEra");
}
@ -577,7 +619,7 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
}
@Override
public Era<HijrahChrono> eraOf(int eraValue) {
public Era eraOf(int eraValue) {
switch (eraValue) {
case 0:
return HijrahEra.BEFORE_AH;
@ -589,8 +631,8 @@ public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializ
}
@Override
public List<Era<HijrahChrono>> eras() {
return Arrays.<Era<HijrahChrono>>asList(HijrahEra.values());
public List<Era> eras() {
return Arrays.<Era>asList(HijrahEra.values());
}
//-----------------------------------------------------------------------

View File

@ -54,7 +54,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
@ -68,19 +68,27 @@ import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.util.Objects;
/**
* A date in the Hijrah calendar system.
* <p>
* This implements {@code ChronoLocalDate} for the {@link HijrahChrono Hijrah calendar}.
* This date operates using the {@linkplain HijrahChronology Hijrah calendar}.
* <p>
* The Hijrah calendar has a different total of days in a year than
* Gregorian calendar, and a month is based on the period of a complete
@ -116,11 +124,9 @@ import java.util.Objects;
*
* @since 1.8
*/
final class HijrahDate
extends ChronoDateImpl<HijrahChrono>
implements ChronoLocalDate<HijrahChrono>, Serializable {
// this class is package-scoped so that future conversion to public
// would not change serialization
public final class HijrahDate
extends ChronoDateImpl<HijrahDate>
implements ChronoLocalDate<HijrahDate>, Serializable {
/**
* Serialization version.
@ -130,7 +136,7 @@ final class HijrahDate
/**
* The Chronology of this HijrahDate.
*/
private final HijrahChrono chrono;
private final HijrahChronology chrono;
/**
* The era.
*/
@ -177,7 +183,7 @@ final class HijrahDate
* @return the Hijrah date, never null
* @throws DateTimeException if the value of any field is out of range
*/
static HijrahDate of(HijrahChrono chrono, int prolepticYear, int monthOfYear, int dayOfMonth) {
static HijrahDate of(HijrahChronology chrono, int prolepticYear, int monthOfYear, int dayOfMonth) {
return (prolepticYear >= 1) ?
HijrahDate.of(chrono, HijrahEra.AH, prolepticYear, monthOfYear, dayOfMonth) :
HijrahDate.of(chrono, HijrahEra.BEFORE_AH, 1 - prolepticYear, monthOfYear, dayOfMonth);
@ -194,7 +200,7 @@ final class HijrahDate
* @return the Hijrah date, never null
* @throws DateTimeException if the value of any field is out of range
*/
private static HijrahDate of(HijrahChrono chrono, HijrahEra era, int yearOfEra, int monthOfYear, int dayOfMonth) {
private static HijrahDate of(HijrahChronology chrono, HijrahEra era, int yearOfEra, int monthOfYear, int dayOfMonth) {
Objects.requireNonNull(era, "era");
chrono.checkValidYearOfEra(yearOfEra);
chrono.checkValidMonth(monthOfYear);
@ -203,28 +209,103 @@ final class HijrahDate
return new HijrahDate(chrono, gregorianDays);
}
/**
* Obtains an instance of {@code HijrahDate} from a date.
*
* @param date the date to use, not null
* @return the Hijrah date, never null
* @throws DateTimeException if the year is invalid
*/
private static HijrahDate of(HijrahChrono chrono, LocalDate date) {
long gregorianDays = date.toEpochDay();
return new HijrahDate(chrono, gregorianDays);
}
static HijrahDate ofEpochDay(HijrahChrono chrono, long epochDay) {
static HijrahDate ofEpochDay(HijrahChronology chrono, long epochDay) {
return new HijrahDate(chrono, epochDay);
}
//-----------------------------------------------------------------------
/**
* Obtains the current {@code HijrahDate} from the system clock in the default time-zone.
* <p>
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
* time-zone to obtain the current date.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
* because the clock is hard-coded.
*
* @return the current date using the system clock and default time-zone, not null
*/
public static HijrahDate now() {
return now(Clock.systemDefaultZone());
}
/**
* Obtains the current {@code HijrahDate} from the system clock in the specified time-zone.
* <p>
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
* Specifying the time-zone avoids dependence on the default time-zone.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
* because the clock is hard-coded.
*
* @param zone the zone ID to use, not null
* @return the current date using the system clock, not null
*/
public static HijrahDate now(ZoneId zone) {
return now(Clock.system(zone));
}
/**
* Obtains the current {@code HijrahDate} from the specified clock.
* <p>
* This will query the specified clock to obtain the current date - today.
* Using this method allows the use of an alternate clock for testing.
* The alternate clock may be introduced using {@linkplain Clock dependency injection}.
*
* @param clock the clock to use, not null
* @return the current date, not null
* @throws DateTimeException if the current date cannot be obtained
*/
public static HijrahDate now(Clock clock) {
return HijrahChronology.INSTANCE.date(LocalDate.now(clock));
}
/**
* Obtains a {@code HijrahDate} representing a date in the Hijrah calendar
* system from the proleptic-year, month-of-year and day-of-month fields.
* <p>
* This returns a {@code HijrahDate} with the specified fields.
* The day must be valid for the year and month, otherwise an exception will be thrown.
*
* @param prolepticYear the Hijrah proleptic-year
* @param month the Hijrah month-of-year, from 1 to 12
* @param dayOfMonth the Hijrah day-of-month, from 1 to 30
* @return the date in Hijrah calendar system, not null
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-month is invalid for the month-year
*/
public static HijrahDate of(int prolepticYear, int month, int dayOfMonth) {
return HijrahChronology.INSTANCE.date(prolepticYear, month, dayOfMonth);
}
/**
* Obtains a {@code HijrahDate} from a temporal object.
* <p>
* This obtains a date in the Hijrah calendar system based on the specified temporal.
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
* which this factory converts to an instance of {@code HijrahDate}.
* <p>
* The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
* field, which is standardized across calendar systems.
* <p>
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used as a query via method reference, {@code HijrahDate::from}.
*
* @param temporal the temporal object to convert, not null
* @return the date in Hijrah calendar system, not null
* @throws DateTimeException if unable to convert to a {@code HijrahDate}
*/
public static HijrahDate from(TemporalAccessor temporal) {
return HijrahChronology.INSTANCE.date(temporal);
}
//-----------------------------------------------------------------------
/**
* Constructs an instance with the specified date.
*
* @param gregorianDay the number of days from 0001/01/01 (Gregorian), caller calculated
*/
private HijrahDate(HijrahChrono chrono, long gregorianDay) {
private HijrahDate(HijrahChronology chrono, long gregorianDay) {
this.chrono = chrono;
int[] dateInfo = chrono.getHijrahDateInfo(gregorianDay);
@ -245,7 +326,7 @@ final class HijrahDate
//-----------------------------------------------------------------------
@Override
public HijrahChrono getChrono() {
public HijrahChronology getChronology() {
return chrono;
}
@ -260,11 +341,16 @@ final class HijrahDate
case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, 5); // TODO
case YEAR_OF_ERA: return ValueRange.of(1, 1000); // TODO
}
return getChrono().range(f);
return getChronology().range(f);
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doRange(this);
return field.rangeRefinedBy(this);
}
@Override // Override for javadoc
public int get(TemporalField field) {
return super.get(field);
}
@Override
@ -286,7 +372,7 @@ final class HijrahDate
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
@Override
@ -322,17 +408,41 @@ final class HijrahDate
return HijrahDate.of(chrono, yearOfEra, month, day);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public HijrahDate with(TemporalAdjuster adjuster) {
return (HijrahDate)super.with(adjuster);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public HijrahDate plus(TemporalAmount amount) {
return (HijrahDate)super.plus(amount);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public HijrahDate minus(TemporalAmount amount) {
return (HijrahDate)super.minus(amount);
}
@Override
public long toEpochDay() {
return chrono.getGregorianEpochDay(yearOfEra, monthOfYear, dayOfMonth);
}
//-----------------------------------------------------------------------
@Override
public HijrahEra getEra() {
return this.era;
}
//-----------------------------------------------------------------------
/**
* Checks if the year is a leap year, according to the Hijrah calendar system rules.
@ -346,7 +456,7 @@ final class HijrahDate
//-----------------------------------------------------------------------
@Override
public HijrahDate plusYears(long years) {
HijrahDate plusYears(long years) {
if (years == 0) {
return this;
}
@ -355,7 +465,7 @@ final class HijrahDate
}
@Override
public HijrahDate plusMonths(long months) {
HijrahDate plusMonths(long months) {
if (months == 0) {
return this;
}
@ -372,10 +482,45 @@ final class HijrahDate
}
@Override
public HijrahDate plusDays(long days) {
HijrahDate plusWeeks(long weeksToAdd) {
return (HijrahDate)super.plusWeeks(weeksToAdd);
}
@Override
HijrahDate plusDays(long days) {
return new HijrahDate(chrono, this.gregorianEpochDay + days);
}
@Override
public HijrahDate plus(long amountToAdd, TemporalUnit unit) {
return (HijrahDate)super.plus(amountToAdd, unit);
}
@Override
public HijrahDate minus(long amountToSubtract, TemporalUnit unit) {
return (HijrahDate)super.minus(amountToSubtract, unit);
}
@Override
HijrahDate minusYears(long yearsToSubtract) {
return (HijrahDate)super.minusYears(yearsToSubtract);
}
@Override
HijrahDate minusMonths(long monthsToSubtract) {
return (HijrahDate)super.minusMonths(monthsToSubtract);
}
@Override
HijrahDate minusWeeks(long weeksToSubtract) {
return (HijrahDate)super.minusWeeks(weeksToSubtract);
}
@Override
HijrahDate minusDays(long daysToSubtract) {
return (HijrahDate)super.minusDays(daysToSubtract);
}
/**
* Returns month days from the beginning of year.
*
@ -410,13 +555,37 @@ final class HijrahDate
return chrono.getYearLength(yearOfEra); // TODO: proleptic year
}
@Override // for javadoc and covariant return type
public final ChronoLocalDateTime<HijrahDate> atTime(LocalTime localTime) {
return (ChronoLocalDateTime<HijrahDate>)super.atTime(localTime);
}
@Override
public Period periodUntil(ChronoLocalDate<?> endDate) {
// TODO: untested
HijrahDate end = (HijrahDate) getChronology().date(endDate);
long totalMonths = (end.yearOfEra - this.yearOfEra) * 12 + (end.monthOfYear - this.monthOfYear); // safe
int days = end.dayOfMonth - this.dayOfMonth;
if (totalMonths > 0 && days < 0) {
totalMonths--;
HijrahDate 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);
}
//-----------------------------------------------------------------------
private Object writeReplace() {
return new Ser(Ser.HIJRAH_DATE_TYPE, this);
}
void writeExternal(ObjectOutput out) throws IOException {
// HijrahChrono is implicit in the Hijrah_DATE_TYPE
// HijrahChronology is implicit in the Hijrah_DATE_TYPE
out.writeObject(chrono);
out.writeInt(get(YEAR));
out.writeByte(get(MONTH_OF_YEAR));
@ -434,8 +603,8 @@ final class HijrahDate
return this;
}
static ChronoLocalDate<HijrahChrono> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
HijrahChrono chrono = (HijrahChrono)in.readObject();
static ChronoLocalDate<HijrahDate> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
HijrahChronology chrono = (HijrahChronology)in.readObject();
int year = in.readInt();
int month = in.readByte();
int dayOfMonth = in.readByte();

View File

@ -54,7 +54,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import java.io.BufferedReader;
@ -67,9 +67,8 @@ import java.nio.file.FileSystems;
import java.security.AccessController;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatters;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.util.Arrays;
import java.util.function.Block;
@ -85,7 +84,7 @@ import java.util.function.Block;
* The deviation files are named {@code "hijrah_" + ID}.
* <p>
* The deviation file for a calendar can be overridden by defining the
* property {@code java.time.calendar.HijrahChrono.File.hijrah_<ID>}
* property {@code java.time.chrono.HijrahChronology.File.hijrah_<ID>}
* with the full pathname of the deviation file.
* <p>
* The deviation file is read line by line:
@ -133,7 +132,7 @@ final class HijrahDeviationReader {
* @throws ParseException if the format of the configuration file is wrong.
*/
static boolean readDeviation(String typeId, String calendarType,
Block<HijrahChrono.Deviation> block) throws IOException, ParseException {
Block<HijrahChronology.Deviation> block) throws IOException, ParseException {
InputStream is = getConfigFileInputStream(typeId);
if (is != null) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
@ -141,7 +140,7 @@ final class HijrahDeviationReader {
int num = 0;
while ((line = br.readLine()) != null) {
num++;
HijrahChrono.Deviation entry = parseLine(line, num);
HijrahChronology.Deviation entry = parseLine(line, num);
if (entry != null) {
block.accept(entry);
}
@ -160,7 +159,7 @@ final class HijrahDeviationReader {
* @return an Entry or null if the line is empty.
* @throws ParseException if line has incorrect format.
*/
private static HijrahChrono.Deviation parseLine(final String line, final int num) throws ParseException {
private static HijrahChronology.Deviation parseLine(final String line, final int num) throws ParseException {
int hash = line.indexOf("#");
String nocomment = (hash < 0) ? line : line.substring(0, hash);
String[] split = nocomment.split("\\s");
@ -174,16 +173,16 @@ final class HijrahDeviationReader {
//element [0] is a date
//element [1] is the offset
LocalDate isoDate = DateTimeFormatters.pattern("MMM-dd-yyyy").parse(split[0], LocalDate::from);
LocalDate isoDate = DateTimeFormatter.ofPattern("MMM-dd-yyyy").parse(split[0], LocalDate::from);
int offset = Integer.valueOf(split[1]);
// Convert date to HijrahDate using the default Islamic Calendar
ChronoLocalDate<HijrahChrono> hijrahDate = HijrahChrono.INSTANCE.date(isoDate);
HijrahDate hijrahDate = HijrahChronology.INSTANCE.date(isoDate);
int year = hijrahDate.get(ChronoField.YEAR);
int month = hijrahDate.get(ChronoField.MONTH_OF_YEAR);
return new HijrahChrono.Deviation(year, month, year, month, offset);
return new HijrahChronology.Deviation(year, month, year, month, offset);
}
@ -198,8 +197,8 @@ final class HijrahDeviationReader {
* </pre> The default location and file name can be overridden by setting
* following two Java system properties.
* <pre>
* Location: java.time.calendar.HijrahDate.deviationConfigDir
* File name: java.time.calendar.HijrahDate.File. + typeid
* Location: java.time.chrono.HijrahDate.deviationConfigDir
* File name: java.time.chrono.HijrahDate.File. + typeid
* </pre> Regarding the file format, see readDeviationConfig() method for
* details.
*
@ -209,10 +208,9 @@ final class HijrahDeviationReader {
*/
private static InputStream getConfigFileInputStream(final String typeId) throws IOException {
try {
InputStream stream =
(InputStream)AccessController
.doPrivileged((java.security.PrivilegedExceptionAction) () -> {
String propFilename = "java.time.calendar.HijrahChrono.File." + typeId;
InputStream stream = AccessController
.doPrivileged((java.security.PrivilegedExceptionAction<InputStream>) () -> {
String propFilename = "java.time.chrono.HijrahChronology.File." + typeId;
String filename = System.getProperty(propFilename);
File file = null;
if (filename != null) {

View File

@ -54,23 +54,12 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
import static java.time.temporal.ChronoField.ERA;
package java.time.chrono;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.time.DateTimeException;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.Era;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalField;
import java.time.temporal.ValueRange;
import java.util.Locale;
/**
* An era in the Hijrah calendar system.
@ -86,7 +75,7 @@ import java.util.Locale;
*
* @since 1.8
*/
enum HijrahEra implements Era<HijrahChrono> {
enum HijrahEra implements Era {
/**
* The singleton instance for the era before the current one, 'Before Anno Hegirae',
@ -135,71 +124,23 @@ enum HijrahEra implements Era<HijrahChrono> {
}
@Override
public HijrahChrono getChrono() {
return HijrahChrono.INSTANCE;
public HijrahChronology getChronology() {
return HijrahChronology.INSTANCE;
}
// JDK8 default methods:
//-----------------------------------------------------------------------
@Override
public ChronoLocalDate<HijrahChrono> date(int year, int month, int day) {
return getChrono().date(this, year, month, day);
public HijrahDate date(int year, int month, int day) {
return (HijrahDate)(getChronology().date(this, year, month, day));
}
@Override
public ChronoLocalDate<HijrahChrono> dateYearDay(int year, int dayOfYear) {
return getChrono().dateYearDay(this, year, dayOfYear);
}
//-----------------------------------------------------------------------
@Override
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
return field == ERA;
}
return field != null && field.doIsSupported(this);
}
@Override
public ValueRange range(TemporalField field) {
if (field == ERA) {
return field.range();
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doRange(this);
}
@Override
public int get(TemporalField field) {
if (field == ERA) {
return getValue();
}
return range(field).checkValidIntValue(getLong(field), field);
}
@Override
public long getLong(TemporalField field) {
if (field == ERA) {
return getValue();
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
public HijrahDate dateYearDay(int year, int dayOfYear) {
return (HijrahDate)(getChronology().dateYearDay(this, year, dayOfYear));
}
//-------------------------------------------------------------------------
@Override
public Temporal adjustInto(Temporal temporal) {
return temporal.with(ERA, getValue());
}
//-----------------------------------------------------------------------
@Override
public String getText(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this);
}
/**
* Returns the proleptic year from this era and year of era.
*

View File

@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time.chrono;
import java.io.Serializable;
import java.time.Clock;
@ -69,6 +69,9 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.ValueRange;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@ -102,26 +105,26 @@ import java.util.Objects;
*
* @since 1.8
*/
public final class ISOChrono extends Chrono<ISOChrono> implements Serializable {
public final class IsoChronology extends Chronology implements Serializable {
/**
* Singleton instance of the ISO chronology.
*/
public static final ISOChrono INSTANCE = new ISOChrono();
public static final IsoChronology INSTANCE = new IsoChronology();
/**
* The singleton instance for the era BCE - 'Before Current Era'.
* The 'ISO' part of the name emphasizes that this differs from the BCE
* era in the Gregorian calendar system.
* This has the numeric value of {@code 0}.
*/
public static final Era<ISOChrono> ERA_BCE = ISOEra.BCE;
public static final Era ERA_BCE = IsoEra.BCE;
/**
* The singleton instance for the era CE - 'Current Era'.
* The 'ISO' part of the name emphasizes that this differs from the CE
* era in the Gregorian calendar system.
* This has the numeric value of {@code 1}.
*/
public static final Era<ISOChrono> ERA_CE = ISOEra.CE;
public static final Era ERA_CE = IsoEra.CE;
/**
* Serialization version.
@ -131,7 +134,7 @@ public final class ISOChrono extends Chrono<ISOChrono> implements Serializable {
/**
* Restricted constructor.
*/
private ISOChrono() {
private IsoChronology() {
}
/**
@ -147,8 +150,8 @@ public final class ISOChrono extends Chrono<ISOChrono> implements Serializable {
/**
* Gets the ID of the chronology - 'ISO'.
* <p>
* The ID uniquely identifies the {@code Chrono}.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* The ID uniquely identifies the {@code Chronology}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
*
* @return the chronology ID - 'ISO'
* @see #getCalendarType()
@ -163,7 +166,7 @@ public final class ISOChrono extends Chrono<ISOChrono> implements Serializable {
* <p>
* The calendar type is an identifier defined by the
* <em>Unicode Locale Data Markup Language (LDML)</em> specification.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
* It can also be used as part of a locale, accessible via
* {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
*
@ -188,7 +191,7 @@ public final class ISOChrono extends Chrono<ISOChrono> implements Serializable {
* @throws DateTimeException if unable to create the date
*/
@Override // override with covariant return type
public LocalDate date(Era<ISOChrono> era, int yearOfEra, int month, int dayOfMonth) {
public LocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
}
@ -219,7 +222,7 @@ public final class ISOChrono extends Chrono<ISOChrono> implements Serializable {
* @throws DateTimeException if unable to create the date
*/
@Override // override with covariant return type
public LocalDate dateYearDay(Era<ISOChrono> era, int yearOfEra, int dayOfYear) {
public LocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
}
@ -291,6 +294,7 @@ public final class ISOChrono extends Chrono<ISOChrono> implements Serializable {
* @return the zoned date-time, not null
* @throws DateTimeException if the result exceeds the supported range
*/
@Override
public ZonedDateTime zonedDateTime(Instant instant, ZoneId zone) {
return ZonedDateTime.ofInstant(instant, zone);
}
@ -373,21 +377,21 @@ public final class ISOChrono extends Chrono<ISOChrono> implements Serializable {
}
@Override
public int prolepticYear(Era<ISOChrono> era, int yearOfEra) {
if (era instanceof ISOEra == false) {
throw new DateTimeException("Era must be ISOEra");
public int prolepticYear(Era era, int yearOfEra) {
if (era instanceof IsoEra == false) {
throw new DateTimeException("Era must be IsoEra");
}
return (era == ISOEra.CE ? yearOfEra : 1 - yearOfEra);
return (era == IsoEra.CE ? yearOfEra : 1 - yearOfEra);
}
@Override
public Era<ISOChrono> eraOf(int eraValue) {
return ISOEra.of(eraValue);
public Era eraOf(int eraValue) {
return IsoEra.of(eraValue);
}
@Override
public List<Era<ISOChrono>> eras() {
return Arrays.<Era<ISOChrono>>asList(ISOEra.values());
public List<Era> eras() {
return Arrays.<Era>asList(IsoEra.values());
}
//-----------------------------------------------------------------------

View File

@ -59,14 +59,11 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time.chrono;
import static java.time.temporal.ChronoField.ERA;
import java.time.DateTimeException;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.util.Locale;
import java.time.LocalDate;
/**
* An era in the ISO calendar system.
@ -75,7 +72,7 @@ import java.util.Locale;
* A definition has therefore been created with two eras - 'Current era' (CE) for
* years from 0001-01-01 (ISO) and 'Before current era' (BCE) for years before that.
* <p>
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code ISOEra}.
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code IsoEra}.
* Use {@code getValue()} instead.</b>
*
* <h3>Specification for implementors</h3>
@ -83,7 +80,7 @@ import java.util.Locale;
*
* @since 1.8
*/
enum ISOEra implements Era<ISOChrono> {
enum IsoEra implements Era {
/**
* The singleton instance for the era BCE, 'Before Current Era'.
@ -102,16 +99,16 @@ enum ISOEra implements Era<ISOChrono> {
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code ISOEra} from an {@code int} value.
* Obtains an instance of {@code IsoEra} from an {@code int} value.
* <p>
* {@code ISOEra} is an enum representing the ISO eras of BCE/CE.
* {@code IsoEra} is an enum representing the ISO eras of BCE/CE.
* This factory allows the enum to be obtained from the {@code int} value.
*
* @param era the BCE/CE value to represent, from 0 (BCE) to 1 (CE)
* @return the era singleton, not null
* @throws DateTimeException if the value is invalid
*/
public static ISOEra of(int era) {
public static IsoEra of(int era) {
switch (era) {
case 0:
return BCE;
@ -136,69 +133,20 @@ enum ISOEra implements Era<ISOChrono> {
}
@Override
public ISOChrono getChrono() {
return ISOChrono.INSTANCE;
public IsoChronology getChronology() {
return IsoChronology.INSTANCE;
}
// JDK8 default methods:
//-----------------------------------------------------------------------
@Override
public ChronoLocalDate<ISOChrono> date(int year, int month, int day) {
return getChrono().date(this, year, month, day);
public LocalDate date(int year, int month, int day) {
return getChronology().date(this, year, month, day);
}
@Override
public ChronoLocalDate<ISOChrono> dateYearDay(int year, int dayOfYear) {
return getChrono().dateYearDay(this, year, dayOfYear);
}
//-----------------------------------------------------------------------
@Override
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
return field == ERA;
}
return field != null && field.doIsSupported(this);
}
@Override
public ValueRange range(TemporalField field) {
if (field == ERA) {
return field.range();
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doRange(this);
}
@Override
public int get(TemporalField field) {
if (field == ERA) {
return getValue();
}
return range(field).checkValidIntValue(getLong(field), field);
}
@Override
public long getLong(TemporalField field) {
if (field == ERA) {
return getValue();
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
}
//-------------------------------------------------------------------------
@Override
public Temporal adjustInto(Temporal temporal) {
return temporal.with(ERA, getValue());
}
//-----------------------------------------------------------------------
@Override
public String getText(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this);
public LocalDate dateYearDay(int year, int dayOfYear) {
return getChronology().dateYearDay(this, year, dayOfYear);
}
}

View File

@ -54,25 +54,22 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.temporal.Chrono;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.Era;
import java.time.temporal.ISOChrono;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.ValueRange;
import java.time.temporal.Year;
import java.time.Year;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import sun.util.calendar.CalendarSystem;
import sun.util.calendar.LocalGregorianCalendar;
@ -93,7 +90,7 @@ import sun.util.calendar.LocalGregorianCalendar;
*
* @since 1.8
*/
public final class JapaneseChrono extends Chrono<JapaneseChrono> implements Serializable {
public final class JapaneseChronology extends Chronology implements Serializable {
// TODO: definition for unknown era may break requirement that year-of-era >= 1
static final LocalGregorianCalendar JCAL =
@ -105,33 +102,33 @@ public final class JapaneseChrono extends Chrono<JapaneseChrono> implements Seri
/**
* Singleton instance for Japanese chronology.
*/
public static final JapaneseChrono INSTANCE = new JapaneseChrono();
public static final JapaneseChronology INSTANCE = new JapaneseChronology();
/**
* The singleton instance for the before Meiji era ( - 1868-09-07)
* which has the value -999.
*/
public static final Era<JapaneseChrono> ERA_SEIREKI = JapaneseEra.SEIREKI;
public static final Era ERA_SEIREKI = JapaneseEra.SEIREKI;
/**
* The singleton instance for the Meiji era (1868-09-08 - 1912-07-29)
* which has the value -1.
*/
public static final Era<JapaneseChrono> ERA_MEIJI = JapaneseEra.MEIJI;
public static final Era ERA_MEIJI = JapaneseEra.MEIJI;
/**
* The singleton instance for the Taisho era (1912-07-30 - 1926-12-24)
* which has the value 0.
*/
public static final Era<JapaneseChrono> ERA_TAISHO = JapaneseEra.TAISHO;
public static final Era ERA_TAISHO = JapaneseEra.TAISHO;
/**
* The singleton instance for the Showa era (1926-12-25 - 1989-01-07)
* which has the value 1.
*/
public static final Era<JapaneseChrono> ERA_SHOWA = JapaneseEra.SHOWA;
public static final Era ERA_SHOWA = JapaneseEra.SHOWA;
/**
* The singleton instance for the Heisei era (1989-01-08 - current)
* which has the value 2.
*/
public static final Era<JapaneseChrono> ERA_HEISEI = JapaneseEra.HEISEI;
public static final Era ERA_HEISEI = JapaneseEra.HEISEI;
/**
* Serialization version.
*/
@ -141,7 +138,7 @@ public final class JapaneseChrono extends Chrono<JapaneseChrono> implements Seri
/**
* Restricted constructor.
*/
private JapaneseChrono() {
private JapaneseChronology() {
}
/**
@ -157,8 +154,8 @@ public final class JapaneseChrono extends Chrono<JapaneseChrono> implements Seri
/**
* Gets the ID of the chronology - 'Japanese'.
* <p>
* The ID uniquely identifies the {@code Chrono}.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* The ID uniquely identifies the {@code Chronology}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
*
* @return the chronology ID - 'Japanese'
* @see #getCalendarType()
@ -173,7 +170,7 @@ public final class JapaneseChrono extends Chrono<JapaneseChrono> implements Seri
* <p>
* The calendar type is an identifier defined by the
* <em>Unicode Locale Data Markup Language (LDML)</em> specification.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
* It can also be used as part of a locale, accessible via
* {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
*
@ -187,7 +184,7 @@ public final class JapaneseChrono extends Chrono<JapaneseChrono> implements Seri
//-----------------------------------------------------------------------
@Override
public ChronoLocalDate<JapaneseChrono> date(Era<JapaneseChrono> era, int yearOfEra, int month, int dayOfMonth) {
public JapaneseDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
if (era instanceof JapaneseEra == false) {
throw new DateTimeException("Era must be JapaneseEra");
}
@ -195,24 +192,59 @@ public final class JapaneseChrono extends Chrono<JapaneseChrono> implements Seri
}
@Override
public ChronoLocalDate<JapaneseChrono> date(int prolepticYear, int month, int dayOfMonth) {
public JapaneseDate date(int prolepticYear, int month, int dayOfMonth) {
return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
}
@Override
public ChronoLocalDate<JapaneseChrono> dateYearDay(int prolepticYear, int dayOfYear) {
public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) {
LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear);
return date(prolepticYear, date.getMonthValue(), date.getDayOfMonth());
}
@Override
public ChronoLocalDate<JapaneseChrono> date(TemporalAccessor temporal) {
public JapaneseDate date(TemporalAccessor temporal) {
if (temporal instanceof JapaneseDate) {
return (JapaneseDate) temporal;
}
return new JapaneseDate(LocalDate.from(temporal));
}
@Override
public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
}
@Override
public JapaneseDate dateNow() {
return dateNow(Clock.systemDefaultZone());
}
@Override
public JapaneseDate dateNow(ZoneId zone) {
return dateNow(Clock.system(zone));
}
@Override
public JapaneseDate dateNow(Clock clock) {
return date(LocalDate.now(clock));
}
@Override
public ChronoLocalDateTime<JapaneseDate> localDateTime(TemporalAccessor temporal) {
return (ChronoLocalDateTime<JapaneseDate>)super.localDateTime(temporal);
}
@Override
public ChronoZonedDateTime<JapaneseDate> zonedDateTime(TemporalAccessor temporal) {
return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(temporal);
}
@Override
public ChronoZonedDateTime<JapaneseDate> zonedDateTime(Instant instant, ZoneId zone) {
return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(instant, zone);
}
//-----------------------------------------------------------------------
/**
* Checks if the specified year is a leap year.
@ -226,11 +258,11 @@ public final class JapaneseChrono extends Chrono<JapaneseChrono> implements Seri
*/
@Override
public boolean isLeapYear(long prolepticYear) {
return ISOChrono.INSTANCE.isLeapYear(prolepticYear);
return IsoChronology.INSTANCE.isLeapYear(prolepticYear);
}
@Override
public int prolepticYear(Era<JapaneseChrono> era, int yearOfEra) {
public int prolepticYear(Era era, int yearOfEra) {
if (era instanceof JapaneseEra == false) {
throw new DateTimeException("Era must be JapaneseEra");
}
@ -261,13 +293,13 @@ public final class JapaneseChrono extends Chrono<JapaneseChrono> implements Seri
* @throws DateTimeException if {@code eraValue} is invalid
*/
@Override
public Era<JapaneseChrono> eraOf(int eraValue) {
public Era eraOf(int eraValue) {
return JapaneseEra.of(eraValue);
}
@Override
public List<Era<JapaneseChrono>> eras() {
return Arrays.<Era<JapaneseChrono>>asList(JapaneseEra.values());
public List<Era> eras() {
return Arrays.<Era>asList(JapaneseEra.values());
}
//-----------------------------------------------------------------------

View File

@ -54,7 +54,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
@ -63,13 +63,20 @@ import static java.time.temporal.ChronoField.YEAR;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.util.Calendar;
import java.util.Objects;
@ -79,19 +86,27 @@ import sun.util.calendar.LocalGregorianCalendar;
/**
* A date in the Japanese Imperial calendar system.
* <p>
* This implements {@code ChronoLocalDate} for the
* {@linkplain JapaneseChrono Japanese Imperial calendar}.
* This date operates using the {@linkplain JapaneseChronology Japanese Imperial calendar}.
* This calendar system is primarily used in Japan.
* <p>
* The Japanese Imperial calendar system is the same as the ISO calendar system
* apart from the era-based year numbering. The proleptic-year is defined to be
* equal to the ISO proleptic-year.
* <p>
* For example, the Japanese year "Heisei 24" corresponds to ISO year "2012".<br>
* Calling {@code japaneseDate.get(YEAR_OF_ERA)} will return 24.<br>
* Calling {@code japaneseDate.get(YEAR)} will return 2012.<br>
* Calling {@code japaneseDate.get(ERA)} will return 2, corresponding to
* {@code JapaneseChronology.ERA_HEISEI}.<br>
*
* <h3>Specification for implementors</h3>
* This class is immutable and thread-safe.
*
* @since 1.8
*/
final class JapaneseDate
extends ChronoDateImpl<JapaneseChrono>
implements ChronoLocalDate<JapaneseChrono>, Serializable {
// this class is package-scoped so that future conversion to public
// would not change serialization
public final class JapaneseDate
extends ChronoDateImpl<JapaneseDate>
implements ChronoLocalDate<JapaneseDate>, Serializable {
/**
* Serialization version.
@ -111,29 +126,159 @@ final class JapaneseDate
*/
private transient int yearOfEra;
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code JapaneseDate} from the era, year-of-era,
* month-of-year and day-of-month.
* Obtains the current {@code JapaneseDate} from the system clock in the default time-zone.
* <p>
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
* time-zone to obtain the current date.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
* because the clock is hard-coded.
*
* @param era the era to represent, not null
* @param yearOfEra the year-of-era to represent
* @param month the month-of-year to represent
* @param dayOfMonth the day-of-month to represent, from 1 to 31
* @return the Japanese date, never null
* @throws DateTimeException if the value of any field is out of range, or
* if the day-of-month is invalid for the month-year
* @return the current date using the system clock and default time-zone, not null
*/
public static JapaneseDate now() {
return now(Clock.systemDefaultZone());
}
/**
* Obtains the current {@code JapaneseDate} from the system clock in the specified time-zone.
* <p>
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
* Specifying the time-zone avoids dependence on the default time-zone.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
* because the clock is hard-coded.
*
* @param zone the zone ID to use, not null
* @return the current date using the system clock, not null
*/
public static JapaneseDate now(ZoneId zone) {
return now(Clock.system(zone));
}
/**
* Obtains the current {@code JapaneseDate} from the specified clock.
* <p>
* This will query the specified clock to obtain the current date - today.
* Using this method allows the use of an alternate clock for testing.
* The alternate clock may be introduced using {@linkplain Clock dependency injection}.
*
* @param clock the clock to use, not null
* @return the current date, not null
* @throws DateTimeException if the current date cannot be obtained
*/
public static JapaneseDate now(Clock clock) {
return JapaneseChronology.INSTANCE.date(LocalDate.now(clock));
}
/**
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
* system from the era, year-of-era, month-of-year and day-of-month fields.
* <p>
* This returns a {@code JapaneseDate} with the specified fields.
* The day must be valid for the year and month, otherwise an exception will be thrown.
*
* @param era the Japanese era, not null
* @param yearOfEra the Japanese year-of-era
* @param month the Japanese month-of-year, from 1 to 12
* @param dayOfMonth the Japanese day-of-month, from 1 to 31
* @return the date in Japanese calendar system, not null
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-month is invalid for the month-year,
* or if the date is not a Japanese era
*/
public static JapaneseDate of(Era era, int yearOfEra, int month, int dayOfMonth) {
if (era instanceof JapaneseEra == false) {
throw new DateTimeException("Era must be JapaneseEra");
}
return JapaneseDate.of((JapaneseEra) era, yearOfEra, month, dayOfMonth);
}
/**
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
* system from the proleptic-year, month-of-year and day-of-month fields.
* <p>
* This returns a {@code JapaneseDate} with the specified fields.
* The day must be valid for the year and month, otherwise an exception will be thrown.
*
* @param prolepticYear the Japanese proleptic-year
* @param month the Japanese month-of-year, from 1 to 12
* @param dayOfMonth the Japanese day-of-month, from 1 to 31
* @return the date in Japanese calendar system, not null
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-month is invalid for the month-year
*/
public static JapaneseDate of(int prolepticYear, int month, int dayOfMonth) {
return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
}
/**
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
* system from the proleptic-year and day-of-year fields.
* <p>
* This returns a {@code JapaneseDate} with the specified fields.
* The day must be valid for the year, otherwise an exception will be thrown.
*
* @param prolepticYear the chronology proleptic-year
* @param dayOfYear the chronology day-of-year, from 1 to 366
* @return the date in Japanese calendar system, not null
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-year is invalid for the year
*/
public static JapaneseDate ofYearDay(int prolepticYear, int dayOfYear) {
LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear);
return of(prolepticYear, date.getMonthValue(), date.getDayOfMonth());
}
/**
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
* system from the era, year-of-era, month-of-year and day-of-month fields.
* <p>
* This returns a {@code JapaneseDate} with the specified fields.
* The day must be valid for the year and month, otherwise an exception will be thrown.
*
* @param era the Japanese era, not null
* @param yearOfEra the Japanese year-of-era
* @param month the Japanese month-of-year, from 1 to 12
* @param dayOfMonth the Japanese day-of-month, from 1 to 31
* @return the date in Japanese calendar system, not null
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-month is invalid for the month-year
*/
static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) {
Objects.requireNonNull(era, "era");
LocalGregorianCalendar.Date jdate = JapaneseChrono.JCAL.newCalendarDate(null);
LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth);
if (!JapaneseChrono.JCAL.validate(jdate)) {
if (!JapaneseChronology.JCAL.validate(jdate)) {
throw new IllegalArgumentException();
}
LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth);
return new JapaneseDate(era, yearOfEra, date);
}
/**
* Obtains a {@code JapaneseDate} from a temporal object.
* <p>
* This obtains a date in the Japanese calendar system based on the specified temporal.
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
* which this factory converts to an instance of {@code JapaneseDate}.
* <p>
* The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
* field, which is standardized across calendar systems.
* <p>
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used as a query via method reference, {@code JapaneseDate::from}.
*
* @param temporal the temporal object to convert, not null
* @return the date in Japanese calendar system, not null
* @throws DateTimeException if unable to convert to a {@code JapaneseDate}
*/
public static JapaneseDate from(TemporalAccessor temporal) {
return JapaneseChronology.INSTANCE.date(temporal);
}
//-----------------------------------------------------------------------
/**
* Creates an instance from an ISO date.
@ -163,8 +308,8 @@ final class JapaneseDate
//-----------------------------------------------------------------------
@Override
public JapaneseChrono getChrono() {
return JapaneseChrono.INSTANCE;
public JapaneseChronology getChronology() {
return JapaneseChronology.INSTANCE;
}
@Override
@ -183,15 +328,15 @@ final class JapaneseDate
case YEAR_OF_ERA:
return actualRange(Calendar.YEAR);
}
return getChrono().range(f);
return getChronology().range(f);
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doRange(this);
return field.rangeRefinedBy(this);
}
private ValueRange actualRange(int calendarField) {
Calendar jcal = Calendar.getInstance(JapaneseChrono.LOCALE);
Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
return ValueRange.of(jcal.getActualMinimum(calendarField),
@ -208,13 +353,13 @@ final class JapaneseDate
return era.getValue();
case DAY_OF_YEAR: {
LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate);
return JapaneseChrono.JCAL.getDayOfYear(jdate);
return JapaneseChronology.JCAL.getDayOfYear(jdate);
}
}
// TODO: review other fields
return isoDate.getLong(field);
}
return field.doGet(this);
return field.getFrom(this);
}
/**
@ -224,14 +369,14 @@ final class JapaneseDate
* @return a {@code LocalGregorianCalendar.Date}, not null
*/
private static LocalGregorianCalendar.Date toPrivateJapaneseDate(LocalDate isoDate) {
LocalGregorianCalendar.Date jdate = JapaneseChrono.JCAL.newCalendarDate(null);
LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
sun.util.calendar.Era sunEra = JapaneseEra.privateEraFrom(isoDate);
int year = isoDate.getYear();
if (sunEra != null) {
year -= sunEra.getSinceDate().getYear() - 1;
}
jdate.setEra(sunEra).setYear(year).setMonth(isoDate.getMonthValue()).setDayOfMonth(isoDate.getDayOfMonth());
JapaneseChrono.JCAL.normalize(jdate);
JapaneseChronology.JCAL.normalize(jdate);
return jdate;
}
@ -266,6 +411,40 @@ final class JapaneseDate
return (JapaneseDate) ChronoLocalDate.super.with(field, newValue);
}
@Override
public Era getEra() {
return era;
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public JapaneseDate with(TemporalAdjuster adjuster) {
return (JapaneseDate)super.with(adjuster);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public JapaneseDate plus(TemporalAmount amount) {
return (JapaneseDate)super.plus(amount);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public JapaneseDate minus(TemporalAmount amount) {
return (JapaneseDate)super.minus(amount);
}
//-----------------------------------------------------------------------
/**
* Returns a copy of this date with the year altered.
@ -282,7 +461,7 @@ final class JapaneseDate
* @throws DateTimeException if {@code year} is invalid
*/
private JapaneseDate withYear(JapaneseEra era, int yearOfEra) {
int year = JapaneseChrono.INSTANCE.prolepticYear(era, yearOfEra);
int year = JapaneseChronology.INSTANCE.prolepticYear(era, yearOfEra);
return with(isoDate.withYear(year));
}
@ -314,15 +493,60 @@ final class JapaneseDate
return with(isoDate.plusMonths(months));
}
@Override
JapaneseDate plusWeeks(long weeksToAdd) {
return with(isoDate.plusWeeks(weeksToAdd));
}
@Override
JapaneseDate plusDays(long days) {
return with(isoDate.plusDays(days));
}
@Override
public JapaneseDate plus(long amountToAdd, TemporalUnit unit) {
return (JapaneseDate)super.plus(amountToAdd, unit);
}
@Override
public JapaneseDate minus(long amountToAdd, TemporalUnit unit) {
return (JapaneseDate)super.minus(amountToAdd, unit);
}
@Override
JapaneseDate minusYears(long yearsToSubtract) {
return (JapaneseDate)super.minusYears(yearsToSubtract);
}
@Override
JapaneseDate minusMonths(long monthsToSubtract) {
return (JapaneseDate)super.minusMonths(monthsToSubtract);
}
@Override
JapaneseDate minusWeeks(long weeksToSubtract) {
return (JapaneseDate)super.minusWeeks(weeksToSubtract);
}
@Override
JapaneseDate minusDays(long daysToSubtract) {
return (JapaneseDate)super.minusDays(daysToSubtract);
}
private JapaneseDate with(LocalDate newDate) {
return (newDate.equals(isoDate) ? this : new JapaneseDate(newDate));
}
@Override // for javadoc and covariant return type
public final ChronoLocalDateTime<JapaneseDate> atTime(LocalTime localTime) {
return (ChronoLocalDateTime<JapaneseDate>)super.atTime(localTime);
}
@Override
public Period periodUntil(ChronoLocalDate<?> endDate) {
return isoDate.periodUntil(endDate);
}
@Override // override for performance
public long toEpochDay() {
return isoDate.toEpochDay();
@ -343,13 +567,13 @@ final class JapaneseDate
@Override // override for performance
public int hashCode() {
return getChrono().getId().hashCode() ^ isoDate.hashCode();
return getChronology().getId().hashCode() ^ isoDate.hashCode();
}
@Override
public String toString() {
if (era == JapaneseEra.SEIREKI) {
return getChrono().getId() + " " + isoDate.toString();
return getChronology().getId() + " " + isoDate.toString();
}
return super.toString();
}
@ -360,18 +584,17 @@ final class JapaneseDate
}
void writeExternal(DataOutput out) throws IOException {
// JapaneseChrono is implicit in the JAPANESE_DATE_TYPE
// JapaneseChronology is implicit in the JAPANESE_DATE_TYPE
out.writeInt(get(YEAR));
out.writeByte(get(MONTH_OF_YEAR));
out.writeByte(get(DAY_OF_MONTH));
}
static ChronoLocalDate<JapaneseChrono> readExternal(DataInput in) throws IOException {
static JapaneseDate readExternal(DataInput in) throws IOException {
int year = in.readInt();
int month = in.readByte();
int dayOfMonth = in.readByte();
return JapaneseChrono.INSTANCE.date(year, month, dayOfMonth);
return JapaneseChronology.INSTANCE.date(year, month, dayOfMonth);
}
}

View File

@ -54,7 +54,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import java.io.DataInput;
import java.io.DataOutput;
@ -64,7 +64,6 @@ import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.temporal.Era;
import java.util.Arrays;
import sun.util.calendar.CalendarDate;
@ -86,7 +85,7 @@ import sun.util.calendar.CalendarDate;
* @since 1.8
*/
final class JapaneseEra
implements Era<JapaneseChrono>, Serializable {
implements Era, Serializable {
// The offset value to 0-based index from the era value.
// i.e., getValue() + ERA_OFFSET == 0-based index; except that -999 is mapped to zero
@ -133,7 +132,7 @@ final class JapaneseEra
private static final JapaneseEra[] KNOWN_ERAS;
static {
sun.util.calendar.Era[] sunEras = JapaneseChrono.JCAL.getEras();
sun.util.calendar.Era[] sunEras = JapaneseChronology.JCAL.getEras();
ERA_CONFIG = new sun.util.calendar.Era[sunEras.length + 1];
for (int i = 1; i < ERA_CONFIG.length; i++) {
ERA_CONFIG[i] = sunEras[i - 1];
@ -292,8 +291,8 @@ final class JapaneseEra
}
@Override
public JapaneseChrono getChrono() {
return JapaneseChrono.INSTANCE;
public JapaneseChronology getChronology() {
return JapaneseChronology.INSTANCE;
}
//-----------------------------------------------------------------------

View File

@ -54,18 +54,17 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import static java.time.temporal.ChronoField.YEAR;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.temporal.Chrono;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.Era;
import java.time.temporal.ISOChrono;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.ValueRange;
import java.util.Arrays;
@ -77,7 +76,7 @@ import java.util.Locale;
* <p>
* This chronology defines the rules of the Minguo calendar system.
* This calendar system is primarily used in the Republic of China, often known as Taiwan.
* Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1911-01-01 (ISO)}.
* Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}.
* <p>
* The fields are defined as follows:
* <p><ul>
@ -100,22 +99,22 @@ import java.util.Locale;
*
* @since 1.8
*/
public final class MinguoChrono extends Chrono<MinguoChrono> implements Serializable {
public final class MinguoChronology extends Chronology implements Serializable {
/**
* Singleton instance for the Minguo chronology.
*/
public static final MinguoChrono INSTANCE = new MinguoChrono();
public static final MinguoChronology INSTANCE = new MinguoChronology();
/**
* The singleton instance for the era ROC.
*/
public static final Era<MinguoChrono> ERA_ROC = MinguoEra.ROC;
public static final Era ERA_ROC = MinguoEra.ROC;
/**
* The singleton instance for the era BEFORE_ROC.
*/
public static final Era<MinguoChrono> ERA_BEFORE_ROC = MinguoEra.BEFORE_ROC;
public static final Era ERA_BEFORE_ROC = MinguoEra.BEFORE_ROC;
/**
* Serialization version.
@ -129,7 +128,7 @@ public final class MinguoChrono extends Chrono<MinguoChrono> implements Serializ
/**
* Restricted constructor.
*/
private MinguoChrono() {
private MinguoChronology() {
}
/**
@ -145,8 +144,8 @@ public final class MinguoChrono extends Chrono<MinguoChrono> implements Serializ
/**
* Gets the ID of the chronology - 'Minguo'.
* <p>
* The ID uniquely identifies the {@code Chrono}.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* The ID uniquely identifies the {@code Chronology}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
*
* @return the chronology ID - 'Minguo'
* @see #getCalendarType()
@ -161,7 +160,7 @@ public final class MinguoChrono extends Chrono<MinguoChrono> implements Serializ
* <p>
* The calendar type is an identifier defined by the
* <em>Unicode Locale Data Markup Language (LDML)</em> specification.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
* It can also be used as part of a locale, accessible via
* {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
*
@ -175,22 +174,62 @@ public final class MinguoChrono extends Chrono<MinguoChrono> implements Serializ
//-----------------------------------------------------------------------
@Override
public ChronoLocalDate<MinguoChrono> date(int prolepticYear, int month, int dayOfMonth) {
public MinguoDate date(int prolepticYear, int month, int dayOfMonth) {
return new MinguoDate(LocalDate.of(prolepticYear + YEARS_DIFFERENCE, month, dayOfMonth));
}
@Override
public ChronoLocalDate<MinguoChrono> dateYearDay(int prolepticYear, int dayOfYear) {
public MinguoDate dateYearDay(int prolepticYear, int dayOfYear) {
return new MinguoDate(LocalDate.ofYearDay(prolepticYear + YEARS_DIFFERENCE, dayOfYear));
}
@Override
public ChronoLocalDate<MinguoChrono> date(TemporalAccessor temporal) {
public MinguoDate date(TemporalAccessor temporal) {
if (temporal instanceof MinguoDate) {
return (MinguoDate) temporal;
}
return new MinguoDate(LocalDate.from(temporal));
}
@Override
public MinguoDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
}
@Override
public MinguoDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
}
@Override
public MinguoDate dateNow() {
return dateNow(Clock.systemDefaultZone());
}
@Override
public MinguoDate dateNow(ZoneId zone) {
return dateNow(Clock.system(zone));
}
@Override
public MinguoDate dateNow(Clock clock) {
return date(LocalDate.now(clock));
}
@Override
public ChronoLocalDateTime<MinguoDate> localDateTime(TemporalAccessor temporal) {
return (ChronoLocalDateTime<MinguoDate>)super.localDateTime(temporal);
}
@Override
public ChronoZonedDateTime<MinguoDate> zonedDateTime(TemporalAccessor temporal) {
return (ChronoZonedDateTime<MinguoDate>)super.zonedDateTime(temporal);
}
@Override
public ChronoZonedDateTime<MinguoDate> zonedDateTime(Instant instant, ZoneId zone) {
return (ChronoZonedDateTime<MinguoDate>)super.zonedDateTime(instant, zone);
}
//-----------------------------------------------------------------------
/**
@ -205,11 +244,11 @@ public final class MinguoChrono extends Chrono<MinguoChrono> implements Serializ
*/
@Override
public boolean isLeapYear(long prolepticYear) {
return ISOChrono.INSTANCE.isLeapYear(prolepticYear + YEARS_DIFFERENCE);
return IsoChronology.INSTANCE.isLeapYear(prolepticYear + YEARS_DIFFERENCE);
}
@Override
public int prolepticYear(Era<MinguoChrono> era, int yearOfEra) {
public int prolepticYear(Era era, int yearOfEra) {
if (era instanceof MinguoEra == false) {
throw new DateTimeException("Era must be MinguoEra");
}
@ -217,13 +256,13 @@ public final class MinguoChrono extends Chrono<MinguoChrono> implements Serializ
}
@Override
public Era<MinguoChrono> eraOf(int eraValue) {
public Era eraOf(int eraValue) {
return MinguoEra.of(eraValue);
}
@Override
public List<Era<MinguoChrono>> eras() {
return Arrays.<Era<MinguoChrono>>asList(MinguoEra.values());
public List<Era> eras() {
return Arrays.<Era>asList(MinguoEra.values());
}
//-----------------------------------------------------------------------

View File

@ -54,9 +54,9 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import static java.time.calendar.MinguoChrono.YEARS_DIFFERENCE;
import static java.time.chrono.MinguoChronology.YEARS_DIFFERENCE;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.YEAR;
@ -65,29 +65,37 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.util.Objects;
/**
* A date in the Minguo calendar system.
* <p>
* This implements {@code ChronoLocalDate} for the {@link MinguoChrono Minguo calendar}.
* This date operates using the {@linkplain MinguoChronology Minguo calendar}.
* This calendar system is primarily used in the Republic of China, often known as Taiwan.
* Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}.
*
* <h3>Specification for implementors</h3>
* This class is immutable and thread-safe.
*
* @since 1.8
*/
final class MinguoDate
extends ChronoDateImpl<MinguoChrono>
implements ChronoLocalDate<MinguoChrono>, Serializable {
// this class is package-scoped so that future conversion to public
// would not change serialization
public final class MinguoDate
extends ChronoDateImpl<MinguoDate>
implements ChronoLocalDate<MinguoDate>, Serializable {
/**
* Serialization version.
@ -99,6 +107,93 @@ final class MinguoDate
*/
private final LocalDate isoDate;
//-----------------------------------------------------------------------
/**
* Obtains the current {@code MinguoDate} from the system clock in the default time-zone.
* <p>
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
* time-zone to obtain the current date.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
* because the clock is hard-coded.
*
* @return the current date using the system clock and default time-zone, not null
*/
public static MinguoDate now() {
return now(Clock.systemDefaultZone());
}
/**
* Obtains the current {@code MinguoDate} from the system clock in the specified time-zone.
* <p>
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
* Specifying the time-zone avoids dependence on the default time-zone.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
* because the clock is hard-coded.
*
* @param zone the zone ID to use, not null
* @return the current date using the system clock, not null
*/
public static MinguoDate now(ZoneId zone) {
return now(Clock.system(zone));
}
/**
* Obtains the current {@code MinguoDate} from the specified clock.
* <p>
* This will query the specified clock to obtain the current date - today.
* Using this method allows the use of an alternate clock for testing.
* The alternate clock may be introduced using {@linkplain Clock dependency injection}.
*
* @param clock the clock to use, not null
* @return the current date, not null
* @throws DateTimeException if the current date cannot be obtained
*/
public static MinguoDate now(Clock clock) {
return MinguoChronology.INSTANCE.date(LocalDate.now(clock));
}
/**
* Obtains a {@code MinguoDate} representing a date in the Minguo calendar
* system from the proleptic-year, month-of-year and day-of-month fields.
* <p>
* This returns a {@code MinguoDate} with the specified fields.
* The day must be valid for the year and month, otherwise an exception will be thrown.
*
* @param prolepticYear the Minguo proleptic-year
* @param month the Minguo month-of-year, from 1 to 12
* @param dayOfMonth the Minguo day-of-month, from 1 to 31
* @return the date in Minguo calendar system, not null
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-month is invalid for the month-year
*/
public static MinguoDate of(int prolepticYear, int month, int dayOfMonth) {
return new MinguoDate(LocalDate.of(prolepticYear + YEARS_DIFFERENCE, month, dayOfMonth));
}
/**
* Obtains a {@code MinguoDate} from a temporal object.
* <p>
* This obtains a date in the Minguo calendar system based on the specified temporal.
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
* which this factory converts to an instance of {@code MinguoDate}.
* <p>
* The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
* field, which is standardized across calendar systems.
* <p>
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used as a query via method reference, {@code MinguoDate::from}.
*
* @param temporal the temporal object to convert, not null
* @return the date in Minguo calendar system, not null
* @throws DateTimeException if unable to convert to a {@code MinguoDate}
*/
public static MinguoDate from(TemporalAccessor temporal) {
return MinguoChronology.INSTANCE.date(temporal);
}
//-----------------------------------------------------------------------
/**
* Creates an instance from an ISO date.
*
@ -111,8 +206,8 @@ final class MinguoDate
//-----------------------------------------------------------------------
@Override
public MinguoChrono getChrono() {
return MinguoChrono.INSTANCE;
public MinguoChronology getChronology() {
return MinguoChronology.INSTANCE;
}
@Override
@ -136,11 +231,11 @@ final class MinguoDate
return ValueRange.of(1, max);
}
}
return getChrono().range(f);
return getChronology().range(f);
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doRange(this);
return field.rangeRefinedBy(this);
}
@Override
@ -158,7 +253,7 @@ final class MinguoDate
}
return isoDate.getLong(field);
}
return field.doGet(this);
return field.getFrom(this);
}
private int getProlepticYear() {
@ -194,6 +289,36 @@ final class MinguoDate
return (MinguoDate) ChronoLocalDate.super.with(field, newValue);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public MinguoDate with(TemporalAdjuster adjuster) {
return (MinguoDate)super.with(adjuster);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public MinguoDate plus(TemporalAmount amount) {
return (MinguoDate)super.plus(amount);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public MinguoDate minus(TemporalAmount amount) {
return (MinguoDate)super.minus(amount);
}
//-----------------------------------------------------------------------
@Override
MinguoDate plusYears(long years) {
@ -210,10 +335,55 @@ final class MinguoDate
return with(isoDate.plusDays(days));
}
@Override
public MinguoDate plus(long amountToAdd, TemporalUnit unit) {
return (MinguoDate)super.plus(amountToAdd, unit);
}
@Override
public MinguoDate minus(long amountToAdd, TemporalUnit unit) {
return (MinguoDate)super.minus(amountToAdd, unit);
}
@Override
MinguoDate plusWeeks(long weeksToAdd) {
return (MinguoDate)super.plusWeeks(weeksToAdd);
}
@Override
MinguoDate minusYears(long yearsToSubtract) {
return (MinguoDate)super.minusYears(yearsToSubtract);
}
@Override
MinguoDate minusMonths(long monthsToSubtract) {
return (MinguoDate)super.minusMonths(monthsToSubtract);
}
@Override
MinguoDate minusWeeks(long weeksToSubtract) {
return (MinguoDate)super.minusWeeks(weeksToSubtract);
}
@Override
MinguoDate minusDays(long daysToSubtract) {
return (MinguoDate)super.minusDays(daysToSubtract);
}
private MinguoDate with(LocalDate newDate) {
return (newDate.equals(isoDate) ? this : new MinguoDate(newDate));
}
@Override // for javadoc and covariant return type
public final ChronoLocalDateTime<MinguoDate> atTime(LocalTime localTime) {
return (ChronoLocalDateTime<MinguoDate>)super.atTime(localTime);
}
@Override
public Period periodUntil(ChronoLocalDate<?> endDate) {
return isoDate.periodUntil(endDate);
}
@Override // override for performance
public long toEpochDay() {
return isoDate.toEpochDay();
@ -234,7 +404,7 @@ final class MinguoDate
@Override // override for performance
public int hashCode() {
return getChrono().getId().hashCode() ^ isoDate.hashCode();
return getChronology().getId().hashCode() ^ isoDate.hashCode();
}
//-----------------------------------------------------------------------
@ -243,19 +413,17 @@ final class MinguoDate
}
void writeExternal(DataOutput out) throws IOException {
// MinguoChrono is implicit in the MINGUO_DATE_TYPE
// MinguoChronology is implicit in the MINGUO_DATE_TYPE
out.writeInt(get(YEAR));
out.writeByte(get(MONTH_OF_YEAR));
out.writeByte(get(DAY_OF_MONTH));
}
static ChronoLocalDate<MinguoChrono> readExternal(DataInput in) throws IOException {
static ChronoLocalDate readExternal(DataInput in) throws IOException {
int year = in.readInt();
int month = in.readByte();
int dayOfMonth = in.readByte();
return MinguoChrono.INSTANCE.date(year, month, dayOfMonth);
return MinguoChronology.INSTANCE.date(year, month, dayOfMonth);
}
}

View File

@ -54,23 +54,12 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
import static java.time.temporal.ChronoField.ERA;
package java.time.chrono;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.time.DateTimeException;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.Era;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalField;
import java.time.temporal.ValueRange;
import java.util.Locale;
/**
* An era in the Minguo calendar system.
@ -86,7 +75,7 @@ import java.util.Locale;
*
* @since 1.8
*/
enum MinguoEra implements Era<MinguoChrono> {
enum MinguoEra implements Era {
/**
* The singleton instance for the era BEFORE_ROC, 'Before Republic of China'.
@ -135,72 +124,23 @@ enum MinguoEra implements Era<MinguoChrono> {
}
@Override
public MinguoChrono getChrono() {
return MinguoChrono.INSTANCE;
public MinguoChronology getChronology() {
return MinguoChronology.INSTANCE;
}
// JDK8 default methods:
//-----------------------------------------------------------------------
@Override
public ChronoLocalDate<MinguoChrono> date(int year, int month, int day) {
return getChrono().date(this, year, month, day);
public MinguoDate date(int year, int month, int day) {
return (MinguoDate)(getChronology().date(this, year, month, day));
}
@Override
public ChronoLocalDate<MinguoChrono> dateYearDay(int year, int dayOfYear) {
return getChrono().dateYearDay(this, year, dayOfYear);
}
//-----------------------------------------------------------------------
@Override
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
return field == ERA;
}
return field != null && field.doIsSupported(this);
}
@Override
public ValueRange range(TemporalField field) {
if (field == ERA) {
return field.range();
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doRange(this);
}
@Override
public int get(TemporalField field) {
if (field == ERA) {
return getValue();
}
return range(field).checkValidIntValue(getLong(field), field);
}
@Override
public long getLong(TemporalField field) {
if (field == ERA) {
return getValue();
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
public MinguoDate dateYearDay(int year, int dayOfYear) {
return (MinguoDate)(getChronology().dateYearDay(this, year, dayOfYear));
}
//-------------------------------------------------------------------------
@Override
public Temporal adjustInto(Temporal temporal) {
return temporal.with(ERA, getValue());
}
//-----------------------------------------------------------------------
@Override
public String getText(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this);
}
//-----------------------------------------------------------------------
private Object writeReplace() {
return new Ser(Ser.MINGUO_ERA_TYPE, this);
}

View File

@ -54,7 +54,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import java.io.Externalizable;
import java.io.IOException;
@ -72,7 +72,7 @@ import java.time.LocalDateTime;
* This class wraps the object being serialized, and takes a byte representing the type of the class to
* be serialized. This byte can also be used for versioning the serialization format. In this case another
* byte flag would be used in order to specify an alternative version of the type format.
* For example {@code JAPANESE_DATE_TYPE_VERSION_2 = 21}.
* For example {@code CHRONO_TYPE_VERSION_2 = 21}
* <p>
* In order to serialise the object it writes its byte and then calls back to the appropriate class where
* the serialisation is performed. In order to deserialise the object it read in the type byte, switching
@ -94,16 +94,19 @@ final class Ser implements Externalizable {
/**
* Serialization version.
*/
private static final long serialVersionUID = 7857518227608961174L;
private static final long serialVersionUID = -6103370247208168577L;
static final byte JAPANESE_DATE_TYPE = 1;
static final byte JAPANESE_ERA_TYPE = 2;
static final byte HIJRAH_DATE_TYPE = 3;
static final byte HIJRAH_ERA_TYPE = 4;
static final byte MINGUO_DATE_TYPE = 5;
static final byte MINGUO_ERA_TYPE = 6;
static final byte THAIBUDDHIST_DATE_TYPE = 7;
static final byte THAIBUDDHIST_ERA_TYPE = 8;
static final byte CHRONO_TYPE = 1;
static final byte CHRONO_LOCAL_DATE_TIME_TYPE = 2;
static final byte CHRONO_ZONE_DATE_TIME_TYPE = 3;
static final byte JAPANESE_DATE_TYPE = 4;
static final byte JAPANESE_ERA_TYPE = 5;
static final byte HIJRAH_DATE_TYPE = 6;
static final byte HIJRAH_ERA_TYPE = 7;
static final byte MINGUO_DATE_TYPE = 8;
static final byte MINGUO_ERA_TYPE = 9;
static final byte THAIBUDDHIST_DATE_TYPE = 10;
static final byte THAIBUDDHIST_ERA_TYPE = 11;
/** The type being serialized. */
private byte type;
@ -141,6 +144,15 @@ final class Ser implements Externalizable {
private static void writeInternal(byte type, Object object, ObjectOutput out) throws IOException {
out.writeByte(type);
switch (type) {
case CHRONO_TYPE:
((Chronology) object).writeExternal(out);
break;
case CHRONO_LOCAL_DATE_TIME_TYPE:
((ChronoLocalDateTimeImpl<?>) object).writeExternal(out);
break;
case CHRONO_ZONE_DATE_TIME_TYPE:
((ChronoZonedDateTimeImpl<?>) object).writeExternal(out);
break;
case JAPANESE_DATE_TYPE:
((JapaneseDate) object).writeExternal(out);
break;
@ -189,6 +201,9 @@ final class Ser implements Externalizable {
private static Object readInternal(byte type, ObjectInput in) throws IOException, ClassNotFoundException {
switch (type) {
case CHRONO_TYPE: return Chronology.readExternal(in);
case CHRONO_LOCAL_DATE_TIME_TYPE: return ChronoLocalDateTimeImpl.readExternal(in);
case CHRONO_ZONE_DATE_TIME_TYPE: return ChronoZonedDateTimeImpl.readExternal(in);
case JAPANESE_DATE_TYPE: return JapaneseDate.readExternal(in);
case JAPANESE_ERA_TYPE: return JapaneseEra.readExternal(in);
case HIJRAH_DATE_TYPE: return HijrahDate.readExternal(in);
@ -197,8 +212,7 @@ final class Ser implements Externalizable {
case MINGUO_ERA_TYPE: return MinguoEra.readExternal(in);
case THAIBUDDHIST_DATE_TYPE: return ThaiBuddhistDate.readExternal(in);
case THAIBUDDHIST_ERA_TYPE: return ThaiBuddhistEra.readExternal(in);
default:
throw new StreamCorruptedException("Unknown serialized type");
default: throw new StreamCorruptedException("Unknown serialized type");
}
}

View File

@ -54,18 +54,17 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import static java.time.temporal.ChronoField.YEAR;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.temporal.Chrono;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.Era;
import java.time.temporal.ISOChrono;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.ValueRange;
import java.util.Arrays;
@ -101,21 +100,21 @@ import java.util.Locale;
*
* @since 1.8
*/
public final class ThaiBuddhistChrono extends Chrono<ThaiBuddhistChrono> implements Serializable {
public final class ThaiBuddhistChronology extends Chronology implements Serializable {
/**
* Singleton instance of the Buddhist chronology.
*/
public static final ThaiBuddhistChrono INSTANCE = new ThaiBuddhistChrono();
public static final ThaiBuddhistChronology INSTANCE = new ThaiBuddhistChronology();
/**
* The singleton instance for the era before the current one - Before Buddhist -
* which has the value 0.
*/
public static final Era<ThaiBuddhistChrono> ERA_BEFORE_BE = ThaiBuddhistEra.BEFORE_BE;
public static final Era ERA_BEFORE_BE = ThaiBuddhistEra.BEFORE_BE;
/**
* The singleton instance for the current era - Buddhist - which has the value 1.
*/
public static final Era<ThaiBuddhistChrono> ERA_BE = ThaiBuddhistEra.BE;
public static final Era ERA_BE = ThaiBuddhistEra.BE;
/**
* Serialization version.
@ -164,7 +163,7 @@ public final class ThaiBuddhistChrono extends Chrono<ThaiBuddhistChrono> impleme
/**
* Restricted constructor.
*/
private ThaiBuddhistChrono() {
private ThaiBuddhistChronology() {
}
/**
@ -180,8 +179,8 @@ public final class ThaiBuddhistChrono extends Chrono<ThaiBuddhistChrono> impleme
/**
* Gets the ID of the chronology - 'ThaiBuddhist'.
* <p>
* The ID uniquely identifies the {@code Chrono}.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* The ID uniquely identifies the {@code Chronology}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
*
* @return the chronology ID - 'ThaiBuddhist'
* @see #getCalendarType()
@ -196,7 +195,7 @@ public final class ThaiBuddhistChrono extends Chrono<ThaiBuddhistChrono> impleme
* <p>
* The calendar type is an identifier defined by the
* <em>Unicode Locale Data Markup Language (LDML)</em> specification.
* It can be used to lookup the {@code Chrono} using {@link #of(String)}.
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
* It can also be used as part of a locale, accessible via
* {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
*
@ -210,22 +209,62 @@ public final class ThaiBuddhistChrono extends Chrono<ThaiBuddhistChrono> impleme
//-----------------------------------------------------------------------
@Override
public ChronoLocalDate<ThaiBuddhistChrono> date(int prolepticYear, int month, int dayOfMonth) {
public ThaiBuddhistDate date(int prolepticYear, int month, int dayOfMonth) {
return new ThaiBuddhistDate(LocalDate.of(prolepticYear - YEARS_DIFFERENCE, month, dayOfMonth));
}
@Override
public ChronoLocalDate<ThaiBuddhistChrono> dateYearDay(int prolepticYear, int dayOfYear) {
public ThaiBuddhistDate dateYearDay(int prolepticYear, int dayOfYear) {
return new ThaiBuddhistDate(LocalDate.ofYearDay(prolepticYear - YEARS_DIFFERENCE, dayOfYear));
}
@Override
public ChronoLocalDate<ThaiBuddhistChrono> date(TemporalAccessor temporal) {
public ThaiBuddhistDate date(TemporalAccessor temporal) {
if (temporal instanceof ThaiBuddhistDate) {
return (ThaiBuddhistDate) temporal;
}
return new ThaiBuddhistDate(LocalDate.from(temporal));
}
@Override
public ThaiBuddhistDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
}
@Override
public ThaiBuddhistDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
}
@Override
public ThaiBuddhistDate dateNow() {
return dateNow(Clock.systemDefaultZone());
}
@Override
public ThaiBuddhistDate dateNow(ZoneId zone) {
return dateNow(Clock.system(zone));
}
@Override
public ThaiBuddhistDate dateNow(Clock clock) {
return date(LocalDate.now(clock));
}
@Override
public ChronoLocalDateTime<ThaiBuddhistDate> localDateTime(TemporalAccessor temporal) {
return (ChronoLocalDateTime<ThaiBuddhistDate>)super.localDateTime(temporal);
}
@Override
public ChronoZonedDateTime<ThaiBuddhistDate> zonedDateTime(TemporalAccessor temporal) {
return (ChronoZonedDateTime<ThaiBuddhistDate>)super.zonedDateTime(temporal);
}
@Override
public ChronoZonedDateTime<ThaiBuddhistDate> zonedDateTime(Instant instant, ZoneId zone) {
return (ChronoZonedDateTime<ThaiBuddhistDate>)super.zonedDateTime(instant, zone);
}
//-----------------------------------------------------------------------
/**
@ -240,11 +279,11 @@ public final class ThaiBuddhistChrono extends Chrono<ThaiBuddhistChrono> impleme
*/
@Override
public boolean isLeapYear(long prolepticYear) {
return ISOChrono.INSTANCE.isLeapYear(prolepticYear - YEARS_DIFFERENCE);
return IsoChronology.INSTANCE.isLeapYear(prolepticYear - YEARS_DIFFERENCE);
}
@Override
public int prolepticYear(Era<ThaiBuddhistChrono> era, int yearOfEra) {
public int prolepticYear(Era era, int yearOfEra) {
if (era instanceof ThaiBuddhistEra == false) {
throw new DateTimeException("Era must be BuddhistEra");
}
@ -252,13 +291,13 @@ public final class ThaiBuddhistChrono extends Chrono<ThaiBuddhistChrono> impleme
}
@Override
public Era<ThaiBuddhistChrono> eraOf(int eraValue) {
public Era eraOf(int eraValue) {
return ThaiBuddhistEra.of(eraValue);
}
@Override
public List<Era<ThaiBuddhistChrono>> eras() {
return Arrays.<Era<ThaiBuddhistChrono>>asList(ThaiBuddhistEra.values());
public List<Era> eras() {
return Arrays.<Era>asList(ThaiBuddhistEra.values());
}
//-----------------------------------------------------------------------

View File

@ -54,9 +54,9 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import static java.time.calendar.ThaiBuddhistChrono.YEARS_DIFFERENCE;
import static java.time.chrono.ThaiBuddhistChronology.YEARS_DIFFERENCE;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.YEAR;
@ -65,29 +65,37 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.util.Objects;
/**
* A date in the Thai Buddhist calendar system.
* <p>
* This implements {@code ChronoLocalDate} for the {@link ThaiBuddhistChrono Thai Buddhist calendar}.
* This date operates using the {@linkplain ThaiBuddhistChronology Thai Buddhist calendar}.
* This calendar system is primarily used in Thailand.
* Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}.
*
* <h3>Specification for implementors</h3>
* This class is immutable and thread-safe.
*
* @since 1.8
*/
final class ThaiBuddhistDate
extends ChronoDateImpl<ThaiBuddhistChrono>
implements ChronoLocalDate<ThaiBuddhistChrono>, Serializable {
// this class is package-scoped so that future conversion to public
// would not change serialization
public final class ThaiBuddhistDate
extends ChronoDateImpl<ThaiBuddhistDate>
implements ChronoLocalDate<ThaiBuddhistDate>, Serializable {
/**
* Serialization version.
@ -99,6 +107,93 @@ final class ThaiBuddhistDate
*/
private final LocalDate isoDate;
//-----------------------------------------------------------------------
/**
* Obtains the current {@code ThaiBuddhistDate} from the system clock in the default time-zone.
* <p>
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
* time-zone to obtain the current date.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
* because the clock is hard-coded.
*
* @return the current date using the system clock and default time-zone, not null
*/
public static ThaiBuddhistDate now() {
return now(Clock.systemDefaultZone());
}
/**
* Obtains the current {@code ThaiBuddhistDate} from the system clock in the specified time-zone.
* <p>
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
* Specifying the time-zone avoids dependence on the default time-zone.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
* because the clock is hard-coded.
*
* @param zone the zone ID to use, not null
* @return the current date using the system clock, not null
*/
public static ThaiBuddhistDate now(ZoneId zone) {
return now(Clock.system(zone));
}
/**
* Obtains the current {@code ThaiBuddhistDate} from the specified clock.
* <p>
* This will query the specified clock to obtain the current date - today.
* Using this method allows the use of an alternate clock for testing.
* The alternate clock may be introduced using {@linkplain Clock dependency injection}.
*
* @param clock the clock to use, not null
* @return the current date, not null
* @throws DateTimeException if the current date cannot be obtained
*/
public static ThaiBuddhistDate now(Clock clock) {
return ThaiBuddhistChronology.INSTANCE.date(LocalDate.now(clock));
}
/**
* Obtains a {@code ThaiBuddhistDate} representing a date in the Thai Buddhist calendar
* system from the proleptic-year, month-of-year and day-of-month fields.
* <p>
* This returns a {@code ThaiBuddhistDate} with the specified fields.
* The day must be valid for the year and month, otherwise an exception will be thrown.
*
* @param prolepticYear the Thai Buddhist proleptic-year
* @param month the Thai Buddhist month-of-year, from 1 to 12
* @param dayOfMonth the Thai Buddhist day-of-month, from 1 to 31
* @return the date in Thai Buddhist calendar system, not null
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-month is invalid for the month-year
*/
public static ThaiBuddhistDate of(int prolepticYear, int month, int dayOfMonth) {
return new ThaiBuddhistDate(LocalDate.of(prolepticYear - YEARS_DIFFERENCE, month, dayOfMonth));
}
/**
* Obtains a {@code ThaiBuddhistDate} from a temporal object.
* <p>
* This obtains a date in the Thai Buddhist calendar system based on the specified temporal.
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
* which this factory converts to an instance of {@code ThaiBuddhistDate}.
* <p>
* The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
* field, which is standardized across calendar systems.
* <p>
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used as a query via method reference, {@code ThaiBuddhistDate::from}.
*
* @param temporal the temporal object to convert, not null
* @return the date in Thai Buddhist calendar system, not null
* @throws DateTimeException if unable to convert to a {@code ThaiBuddhistDate}
*/
public static ThaiBuddhistDate from(TemporalAccessor temporal) {
return ThaiBuddhistChronology.INSTANCE.date(temporal);
}
//-----------------------------------------------------------------------
/**
* Creates an instance from an ISO date.
*
@ -111,8 +206,8 @@ final class ThaiBuddhistDate
//-----------------------------------------------------------------------
@Override
public ThaiBuddhistChrono getChrono() {
return ThaiBuddhistChrono.INSTANCE;
public ThaiBuddhistChronology getChronology() {
return ThaiBuddhistChronology.INSTANCE;
}
@Override
@ -136,11 +231,11 @@ final class ThaiBuddhistDate
return ValueRange.of(1, max);
}
}
return getChrono().range(f);
return getChronology().range(f);
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doRange(this);
return field.rangeRefinedBy(this);
}
@Override
@ -158,7 +253,7 @@ final class ThaiBuddhistDate
}
return isoDate.getLong(field);
}
return field.doGet(this);
return field.getFrom(this);
}
private int getProlepticYear() {
@ -194,6 +289,36 @@ final class ThaiBuddhistDate
return (ThaiBuddhistDate) ChronoLocalDate.super.with(field, newValue);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public ThaiBuddhistDate with(TemporalAdjuster adjuster) {
return (ThaiBuddhistDate)super.with(adjuster);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public ThaiBuddhistDate plus(TemporalAmount amount) {
return (ThaiBuddhistDate)super.plus(amount);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public ThaiBuddhistDate minus(TemporalAmount amount) {
return (ThaiBuddhistDate)super.minus(amount);
}
//-----------------------------------------------------------------------
@Override
ThaiBuddhistDate plusYears(long years) {
@ -205,15 +330,60 @@ final class ThaiBuddhistDate
return with(isoDate.plusMonths(months));
}
@Override
ThaiBuddhistDate plusWeeks(long weeksToAdd) {
return (ThaiBuddhistDate)super.plusWeeks(weeksToAdd);
}
@Override
ThaiBuddhistDate plusDays(long days) {
return with(isoDate.plusDays(days));
}
@Override
public ThaiBuddhistDate plus(long amountToAdd, TemporalUnit unit) {
return (ThaiBuddhistDate)super.plus(amountToAdd, unit);
}
@Override
public ThaiBuddhistDate minus(long amountToAdd, TemporalUnit unit) {
return (ThaiBuddhistDate)super.minus(amountToAdd, unit);
}
@Override
ThaiBuddhistDate minusYears(long yearsToSubtract) {
return (ThaiBuddhistDate)super.minusYears(yearsToSubtract);
}
@Override
ThaiBuddhistDate minusMonths(long monthsToSubtract) {
return (ThaiBuddhistDate)super.minusMonths(monthsToSubtract);
}
@Override
ThaiBuddhistDate minusWeeks(long weeksToSubtract) {
return (ThaiBuddhistDate)super.minusWeeks(weeksToSubtract);
}
@Override
ThaiBuddhistDate minusDays(long daysToSubtract) {
return (ThaiBuddhistDate)super.minusDays(daysToSubtract);
}
private ThaiBuddhistDate with(LocalDate newDate) {
return (newDate.equals(isoDate) ? this : new ThaiBuddhistDate(newDate));
}
@Override // for javadoc and covariant return type
public final ChronoLocalDateTime<ThaiBuddhistDate> atTime(LocalTime localTime) {
return (ChronoLocalDateTime<ThaiBuddhistDate>)super.atTime(localTime);
}
@Override
public Period periodUntil(ChronoLocalDate<?> endDate) {
return isoDate.periodUntil(endDate);
}
@Override // override for performance
public long toEpochDay() {
return isoDate.toEpochDay();
@ -234,7 +404,7 @@ final class ThaiBuddhistDate
@Override // override for performance
public int hashCode() {
return getChrono().getId().hashCode() ^ isoDate.hashCode();
return getChronology().getId().hashCode() ^ isoDate.hashCode();
}
//-----------------------------------------------------------------------
@ -243,17 +413,17 @@ final class ThaiBuddhistDate
}
void writeExternal(DataOutput out) throws IOException {
// MinguoChrono is implicit in the THAIBUDDHIST_DATE_TYPE
// ThaiBuddhistChronology is implicit in the THAIBUDDHIST_DATE_TYPE
out.writeInt(this.get(YEAR));
out.writeByte(this.get(MONTH_OF_YEAR));
out.writeByte(this.get(DAY_OF_MONTH));
}
static ChronoLocalDate<ThaiBuddhistChrono> readExternal(DataInput in) throws IOException {
static ThaiBuddhistDate readExternal(DataInput in) throws IOException {
int year = in.readInt();
int month = in.readByte();
int dayOfMonth = in.readByte();
return ThaiBuddhistChrono.INSTANCE.date(year, month, dayOfMonth);
return ThaiBuddhistChronology.INSTANCE.date(year, month, dayOfMonth);
}
}

View File

@ -54,23 +54,13 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.calendar;
package java.time.chrono;
import static java.time.temporal.ChronoField.ERA;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.time.DateTimeException;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoLocalDate;
import java.time.temporal.Era;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalField;
import java.time.temporal.ValueRange;
import java.util.Locale;
/**
* An era in the Thai Buddhist calendar system.
@ -85,7 +75,7 @@ import java.util.Locale;
*
* @since 1.8
*/
enum ThaiBuddhistEra implements Era<ThaiBuddhistChrono> {
enum ThaiBuddhistEra implements Era {
/**
* The singleton instance for the era before the current one, 'Before Buddhist Era',
@ -134,69 +124,20 @@ enum ThaiBuddhistEra implements Era<ThaiBuddhistChrono> {
}
@Override
public ThaiBuddhistChrono getChrono() {
return ThaiBuddhistChrono.INSTANCE;
public ThaiBuddhistChronology getChronology() {
return ThaiBuddhistChronology.INSTANCE;
}
// JDK8 default methods:
//-----------------------------------------------------------------------
@Override
public ChronoLocalDate<ThaiBuddhistChrono> date(int year, int month, int day) {
return getChrono().date(this, year, month, day);
public ThaiBuddhistDate date(int year, int month, int day) {
return (ThaiBuddhistDate)(getChronology().date(this, year, month, day));
}
@Override
public ChronoLocalDate<ThaiBuddhistChrono> dateYearDay(int year, int dayOfYear) {
return getChrono().dateYearDay(this, year, dayOfYear);
}
//-----------------------------------------------------------------------
@Override
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
return field == ERA;
}
return field != null && field.doIsSupported(this);
}
@Override
public ValueRange range(TemporalField field) {
if (field == ERA) {
return field.range();
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doRange(this);
}
@Override
public int get(TemporalField field) {
if (field == ERA) {
return getValue();
}
return range(field).checkValidIntValue(getLong(field), field);
}
@Override
public long getLong(TemporalField field) {
if (field == ERA) {
return getValue();
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
}
//-------------------------------------------------------------------------
@Override
public Temporal adjustInto(Temporal temporal) {
return temporal.with(ERA, getValue());
}
//-----------------------------------------------------------------------
@Override
public String getText(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this);
public ThaiBuddhistDate dateYearDay(int year, int dayOfYear) {
return (ThaiBuddhistDate)(getChronology().dateYearDay(this, year, dayOfYear));
}
//-----------------------------------------------------------------------

View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of JSR-310 nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* <p>
* Generic API for calendar systems other than the default ISO.
* </p>
* <p>
* The main API is based around the calendar system defined in ISO-8601.
* However, there are other calendar systems, and this package provides basic support for them.
* The alternate calendars are provided in the {@link java.time.chrono} package.
* </p>
* <p>
* A calendar system is defined by the {@link java.time.chrono.Chronology} interface,
* while a date in a calendar system is defined by the {@link java.time.chrono.ChronoLocalDate} interface.
* </p>
* <p>
* It is intended that applications use the main API whenever possible, including code to read and write
* from a persistent data store, such as a database, and to send dates and times across a network.
* The "chrono" classes are then used at the user interface level to deal with localized input/output.
* See {@link java.time.chrono.ChronoLocalDate ChronoLocalDate}
* for a full discussion of the issues.
* </p>
* <p>
* Using non-ISO calendar systems in an application introduces significant extra complexity.
* Ensure that the warnings and recommendations in {@code ChronoLocalDate} have been read before
* working with the "chrono" interfaces.
* </p>
* <p>
* The supported calendar systems includes:
* </p>
* <ul>
* <li>{@link java.time.chrono.HijrahChronology Hijrah calendar}</li>
* <li>{@link java.time.chrono.JapaneseChronology Japanese calendar}</li>
* <li>{@link java.time.chrono.MinguoChronology Minguo calendar}</li>
* <li>{@link java.time.chrono.ThaiBuddhistChronology Thai Buddhist calendar}</li>
* </ul>
*
* <h3>Example</h3>
* <p>
* This example lists todays date for all of the available calendars.
* </p>
* <pre>
* // Enumerate the list of available calendars and print todays date for each.
* Set&lt;Chronology&gt; chronos = Chronology.getAvailableChronologies();
* for (Chronology chrono : chronos) {
* ChronoLocalDate&lt;?&gt; date = chrono.dateNow();
* System.out.printf(" %20s: %s%n", chrono.getId(), date.toString());
* }
* </pre>
*
* <p>
* This example creates and uses a date in a named non-ISO calendar system.
* </p>
* <pre>
* // Print the Thai Buddhist date
* ChronoLocalDate&lt;?&gt; now1 = Chronology.of("ThaiBuddhist").dateNow();
* int day = now1.get(ChronoField.DAY_OF_MONTH);
* int dow = now1.get(ChronoField.DAY_OF_WEEK);
* int month = now1.get(ChronoField.MONTH_OF_YEAR);
* int year = now1.get(ChronoField.YEAR);
* System.out.printf(" Today is %s %s %d-%s-%d%n", now1.getChronology().getId(),
* dow, day, month, year);
* // Print today's date and the last day of the year for the Thai Buddhist Calendar.
* ChronoLocalDate&lt;?&gt; first = now1
* .with(ChronoField.DAY_OF_MONTH, 1)
* .with(ChronoField.MONTH_OF_YEAR, 1);
* ChronoLocalDate&lt;?&gt; last = first
* .plus(1, ChronoUnit.YEARS)
* .minus(1, ChronoUnit.DAYS);
* System.out.printf(" %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(),
* first, last);
* </pre>
*
* <p>
* This example creates and uses a date in a specific ThaiBuddhist calendar system.
* </p>
* <pre>
* // Print the Thai Buddhist date
* ThaiBuddhistDate now1 = ThaiBuddhistDate.now();
* int day = now1.get(ChronoField.DAY_OF_MONTH);
* int dow = now1.get(ChronoField.DAY_OF_WEEK);
* int month = now1.get(ChronoField.MONTH_OF_YEAR);
* int year = now1.get(ChronoField.YEAR);
* System.out.printf(" Today is %s %s %d-%s-%d%n", now1.getChronology().getId(),
* dow, day, month, year);
*
* // Print today's date and the last day of the year for the Thai Buddhist Calendar.
* ThaiBuddhistDate first = now1
* .with(ChronoField.DAY_OF_MONTH, 1)
* .with(ChronoField.MONTH_OF_YEAR, 1);
* ThaiBuddhistDate last = first
* .plus(1, ChronoUnit.YEARS)
* .minus(1, ChronoUnit.DAYS);
* System.out.printf(" %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(),
* first, last);
* </pre>
*
* <h3>Package specification</h3>
* <p>
* Unless otherwise noted, passing a null argument to a constructor or method in any class or interface
* in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown.
* The Javadoc "@param" definition is used to summarise the null-behavior.
* The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method.
* </p>
* <p>
* All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
* or a {@link java.time.DateTimeException}.
* </p>
* @since JDK1.8
*/
package java.time.chrono;

View File

@ -74,9 +74,9 @@ import static java.time.temporal.ChronoField.DAY_OF_WEEK;
import static java.time.temporal.ChronoField.DAY_OF_YEAR;
import static java.time.temporal.ChronoField.EPOCH_DAY;
import static java.time.temporal.ChronoField.EPOCH_MONTH;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoField.HOUR_OF_AMPM;
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
import static java.time.temporal.ChronoField.INSTANT_SECONDS;
import static java.time.temporal.ChronoField.MICRO_OF_DAY;
import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
import static java.time.temporal.ChronoField.MILLI_OF_DAY;
@ -86,34 +86,33 @@ import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.NANO_OF_DAY;
import static java.time.temporal.ChronoField.NANO_OF_SECOND;
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
import static java.time.temporal.ChronoField.SECOND_OF_DAY;
import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
import static java.time.temporal.ChronoField.YEAR;
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
import java.time.DateTimeException;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.Chrono;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology;
import java.time.chrono.Era;
import java.time.chrono.IsoChronology;
import java.time.chrono.JapaneseChronology;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Queries;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
/**
* Builder that can holds date and time fields and related date and time objects.
@ -121,12 +120,11 @@ import java.util.Set;
* <b>This class still needs major revision before JDK1.8 ships.</b>
* <p>
* The builder is used to hold onto different elements of date and time.
* It is designed as two separate maps:
* It holds two kinds of object:
* <p><ul>
* <li>from {@link java.time.temporal.TemporalField} to {@code long} value, where the value may be
* outside the valid range for the field
* <li>from {@code Class} to {@link java.time.temporal.TemporalAccessor}, holding larger scale objects
* like {@code LocalDateTime}.
* <li>a {@code Map} from {@link TemporalField} to {@code long} value, where the
* value may be outside the valid range for the field
* <li>a list of objects, such as {@code Chronology} or {@code ZoneId}
* </ul><p>
*
* <h3>Specification for implementors</h3>
@ -135,7 +133,7 @@ import java.util.Set;
*
* @since 1.8
*/
public final class DateTimeBuilder
final class DateTimeBuilder
implements TemporalAccessor, Cloneable {
/**
@ -147,9 +145,21 @@ public final class DateTimeBuilder
*/
private final EnumMap<ChronoField, Long> standardFields = new EnumMap<ChronoField, Long>(ChronoField.class);
/**
* The list of complete date-time objects.
* The chronology.
*/
private final List<Object> objects = new ArrayList<>(2);
private Chronology chrono;
/**
* The zone.
*/
private ZoneId zone;
/**
* The date.
*/
private LocalDate date;
/**
* The time.
*/
private LocalTime time;
//-----------------------------------------------------------------------
/**
@ -158,74 +168,7 @@ public final class DateTimeBuilder
public DateTimeBuilder() {
}
/**
* Creates a new instance of the builder with a single field-value.
* <p>
* This is equivalent to using {@link #addFieldValue(TemporalField, long)} on an empty builder.
*
* @param field the field to add, not null
* @param value the value to add, not null
*/
public DateTimeBuilder(TemporalField field, long value) {
addFieldValue(field, value);
}
/**
* Creates a new instance of the builder.
*
* @param zone the zone, may be null
* @param chrono the chronology, may be null
*/
public DateTimeBuilder(ZoneId zone, Chrono<?> chrono) {
if (zone != null) {
objects.add(zone);
}
if (chrono != null) {
objects.add(chrono);
}
}
//-----------------------------------------------------------------------
/**
* Gets the map of field-value pairs in the builder.
*
* @return a modifiable copy of the field-value map, not null
*/
public Map<TemporalField, Long> getFieldValueMap() {
Map<TemporalField, Long> map = new HashMap<TemporalField, Long>(standardFields);
if (otherFields != null) {
map.putAll(otherFields);
}
return map;
}
/**
* Checks whether the specified field is present in the builder.
*
* @param field the field to find in the field-value map, not null
* @return true if the field is present
*/
public boolean containsFieldValue(TemporalField field) {
Objects.requireNonNull(field, "field");
return standardFields.containsKey(field) || (otherFields != null && otherFields.containsKey(field));
}
/**
* Gets the value of the specified field from the builder.
*
* @param field the field to query in the field-value map, not null
* @return the value of the field, may be out of range
* @throws DateTimeException if the field is not present
*/
public long getFieldValue(TemporalField field) {
Objects.requireNonNull(field, "field");
Long value = getFieldValue0(field);
if (value == null) {
throw new DateTimeException("Field not found: " + field);
}
return value;
}
private Long getFieldValue0(TemporalField field) {
if (field instanceof ChronoField) {
return standardFields.get(field);
@ -235,18 +178,6 @@ public final class DateTimeBuilder
return null;
}
/**
* Gets the value of the specified field from the builder ensuring it is valid.
*
* @param field the field to query in the field-value map, not null
* @return the value of the field, may be out of range
* @throws DateTimeException if the field is not present
*/
public long getValidFieldValue(TemporalField field) {
long value = getFieldValue(field);
return field.range().checkValidValue(value, field);
}
/**
* Adds a field-value pair to the builder.
* <p>
@ -261,7 +192,7 @@ public final class DateTimeBuilder
* @return {@code this}, for method chaining
* @throws DateTimeException if the field is already present with a different value
*/
public DateTimeBuilder addFieldValue(TemporalField field, long value) {
DateTimeBuilder addFieldValue(TemporalField field, long value) {
Objects.requireNonNull(field, "field");
Long old = getFieldValue0(field); // check first for better error message
if (old != null && old.longValue() != value) {
@ -282,125 +213,21 @@ public final class DateTimeBuilder
return this;
}
/**
* Removes a field-value pair from the builder.
* <p>
* This removes a field, which must exist, from the builder.
* See {@link #removeFieldValues(TemporalField...)} for a version which does not throw an exception
*
* @param field the field to remove, not null
* @return the previous value of the field
* @throws DateTimeException if the field is not found
*/
public long removeFieldValue(TemporalField field) {
Objects.requireNonNull(field, "field");
Long value = null;
if (field instanceof ChronoField) {
value = standardFields.remove(field);
} else if (otherFields != null) {
value = otherFields.remove(field);
}
if (value == null) {
throw new DateTimeException("Field not found: " + field);
}
return value;
}
//-----------------------------------------------------------------------
/**
* Removes a list of fields from the builder.
* <p>
* This removes the specified fields from the builder.
* No exception is thrown if the fields are not present.
*
* @param fields the fields to remove, not null
*/
public void removeFieldValues(TemporalField... fields) {
for (TemporalField field : fields) {
if (field instanceof ChronoField) {
standardFields.remove(field);
} else if (otherFields != null) {
otherFields.remove(field);
}
}
void addObject(Chronology chrono) {
this.chrono = chrono;
}
/**
* Queries a list of fields from the builder.
* <p>
* This gets the value of the specified fields from the builder into
* an array where the positions match the order of the fields.
* If a field is not present, the array will contain null in that position.
*
* @param fields the fields to query, not null
* @return the array of field values, not null
*/
public Long[] queryFieldValues(TemporalField... fields) {
Long[] values = new Long[fields.length];
int i = 0;
for (TemporalField field : fields) {
values[i++] = getFieldValue0(field);
}
return values;
void addObject(ZoneId zone) {
this.zone = zone;
}
//-----------------------------------------------------------------------
/**
* Gets the list of date-time objects in the builder.
* <p>
* This map is intended for use with {@link ZoneOffset} and {@link ZoneId}.
* The returned map is live and may be edited.
*
* @return the editable list of date-time objects, not null
*/
public List<Object> getCalendricalList() {
return objects;
void addObject(LocalDate date) {
this.date = date;
}
/**
* Adds a date-time object to the builder.
* <p>
* This adds a date-time object to the builder.
* If the object is a {@code DateTimeBuilder}, each field is added using {@link #addFieldValue}.
* If the object is not already present, then the object is added.
* If the object is already present and it is equal to that specified, no action occurs.
* If the object is already present and it is not equal to that specified, then an exception is thrown.
*
* @param object the object to add, not null
* @return {@code this}, for method chaining
* @throws DateTimeException if the field is already present with a different value
*/
public DateTimeBuilder addCalendrical(Object object) {
Objects.requireNonNull(object, "object");
// special case
if (object instanceof DateTimeBuilder) {
DateTimeBuilder dtb = (DateTimeBuilder) object;
for (TemporalField field : dtb.getFieldValueMap().keySet()) {
addFieldValue(field, dtb.getFieldValue(field));
}
return this;
}
if (object instanceof Instant) {
addFieldValue(INSTANT_SECONDS, ((Instant) object).getEpochSecond());
addFieldValue(NANO_OF_SECOND, ((Instant) object).getNano());
} else {
objects.add(object);
}
// TODO
// // preserve state of builder until validated
// Class<?> cls = dateTime.extract(Class.class);
// if (cls == null) {
// throw new DateTimeException("Invalid dateTime, unable to extract Class");
// }
// Object obj = objects.get(cls);
// if (obj != null) {
// if (obj.equals(dateTime) == false) {
// throw new DateTimeException("Conflict found: " + dateTime.getClass().getSimpleName() + " " + obj + " differs from " + dateTime + ": " + this);
// }
// } else {
// objects.put(cls, dateTime);
// }
return this;
void addObject(LocalTime time) {
this.time = time;
}
//-----------------------------------------------------------------------
@ -413,21 +240,7 @@ public final class DateTimeBuilder
*
* @return {@code this}, for method chaining
*/
public DateTimeBuilder resolve() {
splitObjects();
// handle unusual fields
if (otherFields != null) {
outer:
while (true) {
Set<Entry<TemporalField, Long>> entrySet = new HashSet<>(otherFields.entrySet());
for (Entry<TemporalField, Long> entry : entrySet) {
if (entry.getKey().resolve(this, entry.getValue())) {
continue outer;
}
}
break;
}
}
DateTimeBuilder resolve() {
// handle standard fields
mergeDate();
mergeTime();
@ -441,11 +254,39 @@ public final class DateTimeBuilder
return;
}
// normalize fields
if (standardFields.containsKey(EPOCH_MONTH)) {
long em = standardFields.remove(EPOCH_MONTH);
addFieldValue(MONTH_OF_YEAR, (em % 12) + 1);
addFieldValue(YEAR, (em / 12) + 1970);
Era era = null;
if (chrono == IsoChronology.INSTANCE) {
// normalize fields
if (standardFields.containsKey(EPOCH_MONTH)) {
long em = standardFields.remove(EPOCH_MONTH);
addFieldValue(MONTH_OF_YEAR, (em % 12) + 1);
addFieldValue(YEAR, (em / 12) + 1970);
}
} else {
// TODO: revisit EPOCH_MONTH calculation in non-ISO chronology
// Handle EPOCH_MONTH here for non-ISO Chronology
if (standardFields.containsKey(EPOCH_MONTH)) {
long em = standardFields.remove(EPOCH_MONTH);
ChronoLocalDate<?> chronoDate = chrono.date(LocalDate.ofEpochDay(0L));
chronoDate = chronoDate.plus(em, ChronoUnit.MONTHS);
LocalDate date = LocalDate.ofEpochDay(chronoDate.toEpochDay());
checkDate(date);
return;
}
List<Era> eras = chrono.eras();
if (!eras.isEmpty()) {
if (standardFields.containsKey(ERA)) {
long index = standardFields.remove(ERA);
era = chrono.eraOf((int) index);
} else {
era = eras.get(eras.size() - 1); // current Era
}
if (standardFields.containsKey(YEAR_OF_ERA)) {
Long y = standardFields.remove(YEAR_OF_ERA);
putFieldValue0(YEAR, y);
}
}
}
// build date
@ -455,7 +296,19 @@ public final class DateTimeBuilder
int y = Math.toIntExact(standardFields.remove(YEAR));
int moy = Math.toIntExact(standardFields.remove(MONTH_OF_YEAR));
int dom = Math.toIntExact(standardFields.remove(DAY_OF_MONTH));
checkDate(LocalDate.of(y, moy, dom));
LocalDate date;
if (chrono == IsoChronology.INSTANCE) {
date = LocalDate.of(y, moy, dom);
} else {
ChronoLocalDate<?> chronoDate;
if (era == null) {
chronoDate = chrono.date(y, moy, dom);
} else {
chronoDate = era.date(y, moy, dom);
}
date = LocalDate.ofEpochDay(chronoDate.toEpochDay());
}
checkDate(date);
return;
}
if (standardFields.containsKey(ALIGNED_WEEK_OF_MONTH)) {
@ -464,7 +317,20 @@ public final class DateTimeBuilder
int moy = Math.toIntExact(standardFields.remove(MONTH_OF_YEAR));
int aw = Math.toIntExact(standardFields.remove(ALIGNED_WEEK_OF_MONTH));
int ad = Math.toIntExact(standardFields.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH));
checkDate(LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7 + (ad - 1)));
LocalDate date;
if (chrono == IsoChronology.INSTANCE) {
date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7 + (ad - 1));
} else {
ChronoLocalDate<?> chronoDate;
if (era == null) {
chronoDate = chrono.date(y, moy, 1);
} else {
chronoDate = era.date(y, moy, 1);
}
chronoDate = chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS);
date = LocalDate.ofEpochDay(chronoDate.toEpochDay());
}
checkDate(date);
return;
}
if (standardFields.containsKey(DAY_OF_WEEK)) {
@ -472,7 +338,20 @@ public final class DateTimeBuilder
int moy = Math.toIntExact(standardFields.remove(MONTH_OF_YEAR));
int aw = Math.toIntExact(standardFields.remove(ALIGNED_WEEK_OF_MONTH));
int dow = Math.toIntExact(standardFields.remove(DAY_OF_WEEK));
checkDate(LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow))));
LocalDate date;
if (chrono == IsoChronology.INSTANCE) {
date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow)));
} else {
ChronoLocalDate<?> chronoDate;
if (era == null) {
chronoDate = chrono.date(y, moy, 1);
} else {
chronoDate = era.date(y, moy, 1);
}
chronoDate = chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow)));
date = LocalDate.ofEpochDay(chronoDate.toEpochDay());
}
checkDate(date);
return;
}
}
@ -480,7 +359,19 @@ public final class DateTimeBuilder
if (standardFields.containsKey(DAY_OF_YEAR)) {
int y = Math.toIntExact(standardFields.remove(YEAR));
int doy = Math.toIntExact(standardFields.remove(DAY_OF_YEAR));
checkDate(LocalDate.ofYearDay(y, doy));
LocalDate date;
if (chrono == IsoChronology.INSTANCE) {
date = LocalDate.ofYearDay(y, doy);
} else {
ChronoLocalDate<?> chronoDate;
if (era == null) {
chronoDate = chrono.dateYearDay(y, doy);
} else {
chronoDate = era.dateYearDay(y, doy);
}
date = LocalDate.ofEpochDay(chronoDate.toEpochDay());
}
checkDate(date);
return;
}
if (standardFields.containsKey(ALIGNED_WEEK_OF_YEAR)) {
@ -488,14 +379,40 @@ public final class DateTimeBuilder
int y = Math.toIntExact(standardFields.remove(YEAR));
int aw = Math.toIntExact(standardFields.remove(ALIGNED_WEEK_OF_YEAR));
int ad = Math.toIntExact(standardFields.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR));
checkDate(LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7 + (ad - 1)));
LocalDate date;
if (chrono == IsoChronology.INSTANCE) {
date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7 + (ad - 1));
} else {
ChronoLocalDate<?> chronoDate;
if (era == null) {
chronoDate = chrono.dateYearDay(y, 1);
} else {
chronoDate = era.dateYearDay(y, 1);
}
chronoDate = chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS);
date = LocalDate.ofEpochDay(chronoDate.toEpochDay());
}
checkDate(date);
return;
}
if (standardFields.containsKey(DAY_OF_WEEK)) {
int y = Math.toIntExact(standardFields.remove(YEAR));
int aw = Math.toIntExact(standardFields.remove(ALIGNED_WEEK_OF_YEAR));
int dow = Math.toIntExact(standardFields.remove(DAY_OF_WEEK));
checkDate(LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow))));
LocalDate date;
if (chrono == IsoChronology.INSTANCE) {
date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow)));
} else {
ChronoLocalDate<?> chronoDate;
if (era == null) {
chronoDate = chrono.dateYearDay(y, 1);
} else {
chronoDate = era.dateYearDay(y, 1);
}
chronoDate = chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow)));
date = LocalDate.ofEpochDay(chronoDate.toEpochDay());
}
checkDate(date);
return;
}
}
@ -503,9 +420,7 @@ public final class DateTimeBuilder
}
private void checkDate(LocalDate date) {
// TODO: this doesn't handle aligned weeks over into next month which would otherwise be valid
addCalendrical(date);
addObject(date);
for (ChronoField field : standardFields.keySet()) {
long val1;
try {
@ -594,96 +509,66 @@ public final class DateTimeBuilder
int somVal = Math.toIntExact(som);
if (nos != null) {
int nosVal = Math.toIntExact(nos);
addCalendrical(LocalTime.of(hodVal, mohVal, somVal, nosVal));
addObject(LocalTime.of(hodVal, mohVal, somVal, nosVal));
} else {
addCalendrical(LocalTime.of(hodVal, mohVal, somVal));
addObject(LocalTime.of(hodVal, mohVal, somVal));
}
} else {
addCalendrical(LocalTime.of(hodVal, mohVal));
addObject(LocalTime.of(hodVal, mohVal));
}
} else {
addCalendrical(LocalTime.of(hodVal, 0));
}
}
}
private void splitObjects() {
List<Object> objectsToAdd = new ArrayList<>();
for (Object object : objects) {
if (object instanceof LocalDate || object instanceof LocalTime ||
object instanceof ZoneId || object instanceof Chrono) {
continue;
}
if (object instanceof ZoneOffset || object instanceof Instant) {
objectsToAdd.add(object);
} else if (object instanceof TemporalAccessor) {
// TODO
// TemporalAccessor dt = (TemporalAccessor) object;
// objectsToAdd.add(dt.extract(LocalDate.class));
// objectsToAdd.add(dt.extract(LocalTime.class));
// objectsToAdd.add(dt.extract(ZoneId.class));
// objectsToAdd.add(dt.extract(Chrono.class));
}
}
for (Object object : objectsToAdd) {
if (object != null) {
addCalendrical(object);
addObject(LocalTime.of(hodVal, 0));
}
}
}
//-----------------------------------------------------------------------
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.zoneId()) {
return (R) extract(ZoneId.class);
public boolean isSupported(TemporalField field) {
if (field == null) {
return false;
}
if (query == Queries.offset()) {
ZoneOffset offset = extract(ZoneOffset.class);
if (offset == null && standardFields.containsKey(OFFSET_SECONDS)) {
offset = ZoneOffset.ofTotalSeconds(Math.toIntExact(standardFields.get(OFFSET_SECONDS)));
return standardFields.containsKey(field) ||
(otherFields != null && otherFields.containsKey(field)) ||
(date != null && date.isSupported(field)) ||
(time != null && time.isSupported(field));
}
@Override
public long getLong(TemporalField field) {
Objects.requireNonNull(field, "field");
Long value = getFieldValue0(field);
if (value == null) {
if (date != null && date.isSupported(field)) {
return date.getLong(field);
}
return (R) offset;
if (time != null && time.isSupported(field)) {
return time.getLong(field);
}
throw new DateTimeException("Field not found: " + field);
}
if (query == Queries.chrono()) {
return extract(Chrono.class);
}
// incomplete, so no need to handle PRECISION
return TemporalAccessor.super.query(query);
return value;
}
@SuppressWarnings("unchecked")
public <R> R extract(Class<?> type) {
R result = null;
for (Object obj : objects) {
if (type.isInstance(obj)) {
if (result != null && result.equals(obj) == false) {
throw new DateTimeException("Conflict found: " + type.getSimpleName() + " differs " + result + " vs " + obj + ": " + this);
}
result = (R) obj;
}
}
return result;
}
//-----------------------------------------------------------------------
/**
* Clones this builder, creating a new independent copy referring to the
* same map of fields and objects.
*
* @return the cloned builder, not null
*/
@Override
public DateTimeBuilder clone() {
DateTimeBuilder dtb = new DateTimeBuilder();
dtb.objects.addAll(this.objects);
dtb.standardFields.putAll(this.standardFields);
dtb.standardFields.putAll(this.standardFields);
if (this.otherFields != null) {
dtb.otherFields.putAll(this.otherFields);
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.zoneId()) {
return (R) zone;
} else if (query == Queries.chronology()) {
return (R) chrono;
} else if (query == Queries.localDate()) {
return (R) date;
} else if (query == Queries.localTime()) {
return (R) time;
} else if (query == Queries.zone() || query == Queries.offset()) {
return query.queryFrom(this);
} else if (query == Queries.precision()) {
return null; // not a complete date/time
}
return dtb;
// inline TemporalAccessor.super.query(query) as an optimization
// non-JDK classes are not permitted to make this optimization
return query.queryFrom(this);
}
//-----------------------------------------------------------------------
@ -691,29 +576,20 @@ public final class DateTimeBuilder
public String toString() {
StringBuilder buf = new StringBuilder(128);
buf.append("DateTimeBuilder[");
Map<TemporalField, Long> fields = getFieldValueMap();
Map<TemporalField, Long> fields = new HashMap<>();
fields.putAll(standardFields);
if (otherFields != null) {
fields.putAll(otherFields);
}
if (fields.size() > 0) {
buf.append("fields=").append(fields);
}
if (objects.size() > 0) {
if (fields.size() > 0) {
buf.append(", ");
}
buf.append("objects=").append(objects);
}
buf.append(", ").append(chrono);
buf.append(", ").append(zone);
buf.append(", ").append(date);
buf.append(", ").append(time);
buf.append(']');
return buf.toString();
}
//-----------------------------------------------------------------------
@Override
public boolean isSupported(TemporalField field) {
return field != null && containsFieldValue(field);
}
@Override
public long getLong(TemporalField field) {
return getFieldValue(field);
}
}

Some files were not shown because too many files have changed in this diff Show More