提交 f9756afb 编写于 作者: C chegar

Merge

......@@ -312,6 +312,12 @@ PROPS = content-types.properties
#
CAL_PROPS = calendars.properties
#
# Rule to copy Hijrah-umalqura calendar properties file.
#
HIJRAH_UMALQURA_PROPS = hijrah-config-umalqura.properties
#
# Rule to copy tzmappings file on Windows
#
......@@ -324,7 +330,7 @@ $(TZMAP): $(TZMAPFILE)
$(call chmod-file, 444)
endif
build: $(LIBDIR)/$(PROPS) $(LIBDIR)/$(CAL_PROPS) $(TZMAP)
build: $(LIBDIR)/$(PROPS) $(LIBDIR)/$(CAL_PROPS) $(LIBDIR)/$(HIJRAH_UMALQURA_PROPS) $(TZMAP)
$(LIBDIR)/$(PROPS): $(PLATFORM_SRC)/lib/$(PROPS)
$(install-file)
......@@ -332,6 +338,9 @@ $(LIBDIR)/$(PROPS): $(PLATFORM_SRC)/lib/$(PROPS)
$(LIBDIR)/$(CAL_PROPS): $(SHARE_SRC)/lib/$(CAL_PROPS)
$(install-file)
$(LIBDIR)/$(HIJRAH_UMALQURA_PROPS): $(SHARE_SRC)/lib/$(HIJRAH_UMALQURA_PROPS)
$(install-file)
clean::
$(RM) -r $(LIBDIR)/$(PROPS) $(TZMAP)
......
......@@ -217,7 +217,7 @@ SUNWprivate_1.1 {
Java_java_lang_Throwable_fillInStackTrace;
Java_java_lang_Throwable_getStackTraceDepth;
Java_java_lang_Throwable_getStackTraceElement;
Java_java_lang_UNIXProcess_initIDs;
Java_java_lang_UNIXProcess_init;
Java_java_lang_UNIXProcess_waitForProcessExit;
Java_java_lang_UNIXProcess_forkAndExec;
Java_java_lang_UNIXProcess_destroyProcess;
......
#
# Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
......@@ -105,5 +105,7 @@ FILES_java = \
sun/text/resources/CollationData.java \
\
sun/text/resources/FormatData.java \
sun/text/resources/JavaTimeSupplementary.java \
sun/text/resources/en/FormatData_en.java \
sun/text/resources/en/FormatData_en_US.java
sun/text/resources/en/FormatData_en_US.java \
sun/text/resources/en/JavaTimeSupplementary_en.java \
#
# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
......@@ -26,6 +26,7 @@
FILES_java = \
sun/util/resources/LocaleData.java \
sun/util/resources/OpenListResourceBundle.java \
sun/util/resources/ParallelListResourceBundle.java \
sun/util/resources/LocaleNamesBundle.java \
sun/util/resources/TimeZoneNamesBundle.java \
sun/util/resources/TimeZoneNames.java \
......
#
# 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
......@@ -227,5 +227,54 @@ FILES_java = \
sun/util/resources/sv/TimeZoneNames_sv.java \
sun/util/resources/zh/TimeZoneNames_zh_CN.java \
sun/util/resources/zh/TimeZoneNames_zh_TW.java \
sun/util/resources/zh/TimeZoneNames_zh_HK.java
sun/util/resources/zh/TimeZoneNames_zh_HK.java \
\
sun/text/resources/ar/JavaTimeSupplementary_ar.java \
sun/text/resources/be/JavaTimeSupplementary_be.java \
sun/text/resources/bg/JavaTimeSupplementary_bg.java \
sun/text/resources/ca/JavaTimeSupplementary_ca.java \
sun/text/resources/cs/JavaTimeSupplementary_cs.java \
sun/text/resources/da/JavaTimeSupplementary_da.java \
sun/text/resources/de/JavaTimeSupplementary_de.java \
sun/text/resources/el/JavaTimeSupplementary_el.java \
sun/text/resources/en/JavaTimeSupplementary_en_GB.java \
sun/text/resources/en/JavaTimeSupplementary_en_SG.java \
sun/text/resources/es/JavaTimeSupplementary_es.java \
sun/text/resources/et/JavaTimeSupplementary_et.java \
sun/text/resources/fi/JavaTimeSupplementary_fi.java \
sun/text/resources/fr/JavaTimeSupplementary_fr.java \
sun/text/resources/ga/JavaTimeSupplementary_ga.java \
sun/text/resources/hi/JavaTimeSupplementary_hi_IN.java \
sun/text/resources/hr/JavaTimeSupplementary_hr.java \
sun/text/resources/hu/JavaTimeSupplementary_hu.java \
sun/text/resources/is/JavaTimeSupplementary_is.java \
sun/text/resources/it/JavaTimeSupplementary_it.java \
sun/text/resources/iw/JavaTimeSupplementary_iw.java \
sun/text/resources/iw/JavaTimeSupplementary_iw_IL.java \
sun/text/resources/ja/JavaTimeSupplementary_ja.java \
sun/text/resources/ko/JavaTimeSupplementary_ko.java \
sun/text/resources/lt/JavaTimeSupplementary_lt.java \
sun/text/resources/lv/JavaTimeSupplementary_lv.java \
sun/text/resources/mk/JavaTimeSupplementary_mk.java \
sun/text/resources/ms/JavaTimeSupplementary_ms.java \
sun/text/resources/mt/JavaTimeSupplementary_mt.java \
sun/text/resources/nl/JavaTimeSupplementary_nl.java \
sun/text/resources/no/JavaTimeSupplementary_no.java \
sun/text/resources/pl/JavaTimeSupplementary_pl.java \
sun/text/resources/pt/JavaTimeSupplementary_pt.java \
sun/text/resources/pt/JavaTimeSupplementary_pt_PT.java \
sun/text/resources/ro/JavaTimeSupplementary_ro.java \
sun/text/resources/ru/JavaTimeSupplementary_ru.java \
sun/text/resources/sk/JavaTimeSupplementary_sk.java \
sun/text/resources/sl/JavaTimeSupplementary_sl.java \
sun/text/resources/sq/JavaTimeSupplementary_sq.java \
sun/text/resources/sr/JavaTimeSupplementary_sr.java \
sun/text/resources/sr/JavaTimeSupplementary_sr_Latn.java \
sun/text/resources/sv/JavaTimeSupplementary_sv.java \
sun/text/resources/th/JavaTimeSupplementary_th.java \
sun/text/resources/tr/JavaTimeSupplementary_tr.java \
sun/text/resources/uk/JavaTimeSupplementary_uk.java \
sun/text/resources/vi/JavaTimeSupplementary_vi.java \
sun/text/resources/zh/JavaTimeSupplementary_zh.java \
sun/text/resources/zh/JavaTimeSupplementary_zh_TW.java
......@@ -42,7 +42,6 @@ BUILD_MANIFEST=true
# Time zone data file creation
#
TZDATA_DIR := ../javazic/tzdata
TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION))
TZFILE := \
africa antarctica asia australasia europe northamerica \
pacificnew southamerica backward etcetera \
......@@ -50,9 +49,7 @@ TZFILE := \
TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZFILE))
TZDB_JAR = tzdb.jar
TZDB_DAT = $(LIBDIR)/tzdb.dat
#
# Rules
......@@ -62,13 +59,12 @@ include $(BUILDDIR)/common/Classes.gmk
#
# Add to the build rule
#
build: $(LIBDIR)/$(TZDB_JAR)
build: $(TZDB_DAT)
$(LIBDIR)/$(TZDB_JAR): $(TZFILES)
$(TZDB_DAT): $(TZFILES)
$(prep-target)
echo build tzdb from version $(TZDATA_VER)
$(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar \
-version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(LIBDIR) $(TZFILE)
-srcdir $(TZDATA_DIR) -dstfile $(TZDB_DAT) $(TZFILE)
clean clobber::
$(RM) $(LIBDIR)/$(TZDB_JAR)
$(RM) $(TZDB_DAT)
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -25,6 +25,7 @@
package build.tools.cldrconverter;
import build.tools.cldrconverter.CLDRConverter.DraftType;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
......@@ -88,7 +89,7 @@ abstract class AbstractLDMLHandler<V> extends DefaultHandler {
}
String draftValue = attributes.getValue("draft");
if (draftValue != null) {
return CLDRConverter.draftType > CLDRConverter.DRAFT_MAP.get(draftValue);
return DraftType.getDefault().ordinal() > DraftType.forKeyword(draftValue).ordinal();
}
return false;
}
......
......@@ -266,6 +266,9 @@ class Bundle {
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayNarrows");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "AmPmMarkers");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "narrow.AmPmMarkers");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "QuarterNames");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "QuarterAbbreviations");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "QuarterNarrows");
adjustEraNames(myMap, calendarType);
......@@ -484,25 +487,33 @@ class Bundle {
for (String k : patternKeys) {
if (myMap.containsKey(calendarPrefix + k)) {
int len = patternKeys.length;
List<String> rawPatterns = new ArrayList<>();
List<String> patterns = new ArrayList<>();
List<String> rawPatterns = new ArrayList<>(len);
List<String> patterns = new ArrayList<>(len);
for (int i = 0; i < len; i++) {
String key = calendarPrefix + patternKeys[i];
String pattern = (String) myMap.remove(key);
if (pattern == null) {
pattern = (String) parentsMap.remove(key);
}
rawPatterns.add(i, pattern);
if (pattern != null) {
rawPatterns.add(i, pattern);
patterns.add(i, translateDateFormatLetters(calendarType, pattern));
} else {
patterns.add(i, null);
}
}
// If patterns is empty or has any nulls, discard patterns.
if (patterns.isEmpty()) {
return;
}
for (String p : patterns) {
if (p == null) {
return;
}
}
String key = calendarPrefix + name;
if (!rawPatterns.equals(patterns)) {
myMap.put("cldr." + key, rawPatterns.toArray(new String[len]));
myMap.put("java.time." + key, rawPatterns.toArray(new String[len]));
}
myMap.put(key, patterns.toArray(new String[len]));
break;
......
......@@ -68,25 +68,43 @@ public class CLDRConverter {
static MetaZonesParseHandler handlerMetaZones;
private static BundleGenerator bundleGenerator;
static int draftType;
private static final String DRAFT_UNCONFIRMED = "unconfirmed";
private static final String DRAFT_PROVISIONAL = "provisional";
private static final String DRAFT_CONTRIBUTED = "contributed";
private static final String DRAFT_APPROVED = "approved";
private static final String DRAFT_TRUE = "true";
private static final String DRAFT_FALSE = "false";
private static final String DRAFT_DEFAULT = DRAFT_APPROVED;
static final Map<String, Integer> DRAFT_MAP = new HashMap<>();
static {
DRAFT_MAP.put(DRAFT_UNCONFIRMED, 0);
DRAFT_MAP.put(DRAFT_PROVISIONAL, 1);
DRAFT_MAP.put(DRAFT_CONTRIBUTED, 2);
DRAFT_MAP.put(DRAFT_APPROVED, 3);
DRAFT_MAP.put(DRAFT_TRUE, 0);
DRAFT_MAP.put(DRAFT_FALSE, 2);
draftType = DRAFT_MAP.get(DRAFT_DEFAULT);
};
static enum DraftType {
UNCONFIRMED,
PROVISIONAL,
CONTRIBUTED,
APPROVED;
private static final Map<String, DraftType> map = new HashMap<>();
static {
for (DraftType dt : values()) {
map.put(dt.getKeyword(), dt);
}
}
static private DraftType defaultType = CONTRIBUTED;
private final String keyword;
private DraftType() {
keyword = this.name().toLowerCase(Locale.ROOT);
}
static DraftType forKeyword(String keyword) {
return map.get(keyword);
}
static DraftType getDefault() {
return defaultType;
}
static void setDefault(String keyword) {
defaultType = Objects.requireNonNull(forKeyword(keyword));
}
String getKeyword() {
return keyword;
}
}
static boolean USE_UTF8 = false;
private static boolean verbose;
......@@ -106,7 +124,7 @@ public class CLDRConverter {
case "-draft":
String draftDataType = args[++i];
try {
draftType = DRAFT_MAP.get(draftDataType);
DraftType.setDefault(draftDataType);
} catch (NullPointerException e) {
severe("Error: incorrect draft value: %s%n", draftDataType);
System.exit(1);
......@@ -525,7 +543,7 @@ public class CLDRConverter {
"standalone.MonthNames",
"MonthAbbreviations",
"standalone.MonthAbbreviations",
"MonthNarrow",
"MonthNarrows",
"standalone.MonthNarrows",
"DayNames",
"standalone.DayNames",
......@@ -533,6 +551,12 @@ public class CLDRConverter {
"standalone.DayAbbreviations",
"DayNarrows",
"standalone.DayNarrows",
"QuarterNames",
"standalone.QuarterNames",
"QuarterAbbreviations",
"standalone.QuarterAbbreviations",
"QuarterNarrows",
"standalone.QuarterNarrows",
"AmPmMarkers",
"narrow.AmPmMarkers",
"long.Eras",
......@@ -560,7 +584,7 @@ public class CLDRConverter {
String prefix = calendarType.keyElementName();
for (String element : FORMAT_DATA_ELEMENTS) {
String key = prefix + element;
copyIfPresent(map, "cldr." + key, formatData);
copyIfPresent(map, "java.time." + key, formatData);
copyIfPresent(map, key, formatData);
}
}
......
......@@ -356,6 +356,44 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
}
}
break;
case "quarterContext":
{
// for FormatData
// need to keep stand-alone and format, to allow for inheritance in CLDR
String type = attributes.getValue("type");
if ("stand-alone".equals(type) || "format".equals(type)) {
pushKeyContainer(qName, attributes, type);
} else {
pushIgnoredContainer(qName);
}
}
break;
case "quarterWidth":
{
// for FormatData
// keep info about the context type so we can sort out inheritance later
String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName();
switch (attributes.getValue("type")) {
case "wide":
pushStringArrayEntry(qName, attributes, prefix + "QuarterNames/" + getContainerKey(), 4);
break;
case "abbreviated":
pushStringArrayEntry(qName, attributes, prefix + "QuarterAbbreviations/" + getContainerKey(), 4);
break;
case "narrow":
pushStringArrayEntry(qName, attributes, prefix + "QuarterNarrows/" + getContainerKey(), 4);
break;
default:
pushIgnoredContainer(qName);
break;
}
}
break;
case "quarter":
// for FormatData
// add to string array entry of quarterWidth element
pushStringArrayElement(qName, attributes, Integer.parseInt(attributes.getValue("type")) - 1);
break;
//
// Time zone names
......
......@@ -174,6 +174,13 @@ $(LIBDIR)/calendars.properties: $(CALENDARS_SRC)/calendars.properties
COPY_FILES += $(LIBDIR)/calendars.properties
$(LIBDIR)/hijrah-config-umalqura.properties: $(CALENDARS_SRC)/hijrah-config-umalqura.properties
$(MKDIR) -p $(@D)
$(RM) $@
$(CP) $< $@
COPY_FILES += $(LIBDIR)/hijrah-config-umalqura.properties
##########################################################################################
ifeq ($(OPENJDK_TARGET_OS),windows)
......
......@@ -73,11 +73,6 @@ $(eval $(call SetupArchive,BUILD_DNS_JAR,,\
##########################################################################################
$(IMAGES_OUTPUTDIR)/lib/tzdb.jar: $(JDK_OUTPUTDIR)/lib/tzdb.jar
$(install-file)
##########################################################################################
LOCALEDATA_INCLUDE_LOCALES := ar be bg ca cs da de el es et fi fr ga hi hr hu in is it \
iw ja ko lt lv mk ms mt nl no pl pt ro ru sk sl sq sr sv \
th tr uk vi zh
......
......@@ -29,16 +29,13 @@ GENDATA_TZDB :=
# Time zone data file creation
#
TZDATA_DIR := $(JDK_TOPDIR)/make/sun/javazic/tzdata
TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION))
TZDATA_TZFILE := africa antarctica asia australasia europe northamerica pacificnew southamerica backward etcetera gmt jdk11_backward
TZDATA_TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZDATA_TZFILE))
GENDATA_TZDB_DST := $(JDK_OUTPUTDIR)/lib
GENDATA_TZDB_JAR := tzdb.jar
GENDATA_TZDB_DAT := $(JDK_OUTPUTDIR)/lib/tzdb.dat
$(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR) : $(TZDATA_TZFILES)
$(RM) $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)
echo building tzdb from version $(TZDATA_VER)
$(TOOL_TZDB) -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(GENDATA_TZDB_DST) $(TZDATA_TZFILE)
$(GENDATA_TZDB_DAT) : $(TZDATA_TZFILES)
$(RM) $(GENDATA_TZDB_DAT)
$(TOOL_TZDB) -srcdir $(TZDATA_DIR) -dstfile $(GENDATA_TZDB_DAT) $(TZDATA_TZFILE)
GENDATA_TZDB += $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)
GENDATA_TZDB += $(GENDATA_TZDB_DAT)
......@@ -217,7 +217,7 @@ SUNWprivate_1.1 {
Java_java_lang_Throwable_fillInStackTrace;
Java_java_lang_Throwable_getStackTraceDepth;
Java_java_lang_Throwable_getStackTraceElement;
Java_java_lang_UNIXProcess_initIDs;
Java_java_lang_UNIXProcess_init;
Java_java_lang_UNIXProcess_waitForProcessExit;
Java_java_lang_UNIXProcess_forkAndExec;
Java_java_lang_UNIXProcess_destroyProcess;
......
......@@ -66,6 +66,7 @@ PROFILE_1_JRE_LIB_FILES := \
ext/sunec.jar \
ext/sunjce_provider.jar \
ext/sunpkcs11.jar \
hijrah-config-umalqura.properties \
jce.jar \
jsse.jar \
logging.properties \
......@@ -80,7 +81,7 @@ PROFILE_1_JRE_LIB_FILES := \
security/java.security \
security/local_policy.jar \
security/trusted.libraries \
tzdb.jar
tzdb.dat
PROFILE_1_JRE_OTHER_FILES := \
COPYRIGHT \
......@@ -100,9 +101,7 @@ PROFILE_1_JRE_JAR_FILES := \
resources.jar \
rt.jar \
security/US_export_policy.jar \
security/local_policy.jar \
tzdb.jar
security/local_policy.jar
PROFILE_2_JRE_BIN_FILES := \
rmid$(EXE_SUFFIX) \
......
......@@ -184,7 +184,7 @@ import java.security.PrivilegedAction;
for (int i=0; i<markerInterfaces.length; i++) {
interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/');
}
cw.visit(CLASSFILE_VERSION, ACC_SUPER,
cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
lambdaClassName, null,
NAME_MAGIC_ACCESSOR_IMPL, interfaces);
......
......@@ -25,12 +25,10 @@
package java.nio.file.attribute;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Date;
import java.util.Formatter;
import java.util.Locale;
import java.util.TimeZone;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
......@@ -51,42 +49,35 @@ public final class FileTime
implements Comparable<FileTime>
{
/**
* The value since the epoch; can be negative.
*/
private final long value;
/**
* The unit of granularity to interpret the value.
* The unit of granularity to interpret the value. Null if
* this {@code FileTime} is converted from an {@code Instant},
* the {@code value} and {@code unit} pair will not be used
* in this scenario.
*/
private final TimeUnit unit;
/**
* The value return by toString (created lazily)
* The value since the epoch; can be negative.
*/
private String valueAsString;
private final long value;
/**
* The value in days and excess nanos (created lazily)
* The value as Instant (created lazily, if not from an instant)
*/
private DaysAndNanos daysAndNanos;
private Instant instant;
/**
* Returns a DaysAndNanos object representing the value.
* The value return by toString (created lazily)
*/
private DaysAndNanos asDaysAndNanos() {
if (daysAndNanos == null)
daysAndNanos = new DaysAndNanos(value, unit);
return daysAndNanos;
}
private String valueAsString;
/**
* Initializes a new instance of this class.
*/
private FileTime(long value, TimeUnit unit) {
if (unit == null)
throw new NullPointerException();
private FileTime(long value, TimeUnit unit, Instant instant) {
this.value = value;
this.unit = unit;
this.instant = instant;
}
/**
......@@ -102,7 +93,8 @@ public final class FileTime
* @return a {@code FileTime} representing the given value
*/
public static FileTime from(long value, TimeUnit unit) {
return new FileTime(value, unit);
Objects.requireNonNull(unit, "unit");
return new FileTime(value, unit, null);
}
/**
......@@ -115,7 +107,22 @@ public final class FileTime
* @return a {@code FileTime} representing the given value
*/
public static FileTime fromMillis(long value) {
return new FileTime(value, TimeUnit.MILLISECONDS);
return new FileTime(value, TimeUnit.MILLISECONDS, null);
}
/**
* Returns a {@code FileTime} representing the same point of time value
* on the time-line as the provided {@code Instant} object.
*
* @param instant
* the instant to convert
* @return a {@code FileTime} representing the same point on the time-line
* as the provided instant
* @since 1.8
*/
public static FileTime from(Instant instant) {
Objects.requireNonNull(instant, "instant");
return new FileTime(0, null, instant);
}
/**
......@@ -132,7 +139,22 @@ public final class FileTime
* since the epoch (1970-01-01T00:00:00Z); can be negative
*/
public long to(TimeUnit unit) {
return unit.convert(this.value, this.unit);
Objects.requireNonNull(unit, "unit");
if (this.unit != null) {
return unit.convert(this.value, this.unit);
} else {
long secs = unit.convert(instant.getEpochSecond(), TimeUnit.SECONDS);
if (secs == Long.MIN_VALUE || secs == Long.MAX_VALUE) {
return secs;
}
long nanos = unit.convert(instant.getNano(), TimeUnit.NANOSECONDS);
long r = secs + nanos;
// Math.addExact() variant
if (((secs ^ r) & (nanos ^ r)) < 0) {
return (secs < 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
}
return r;
}
}
/**
......@@ -145,7 +167,110 @@ public final class FileTime
* @return the value in milliseconds, since the epoch (1970-01-01T00:00:00Z)
*/
public long toMillis() {
return unit.toMillis(value);
if (unit != null) {
return unit.toMillis(value);
} else {
long secs = instant.getEpochSecond();
int nanos = instant.getNano();
// Math.multiplyExact() variant
long r = secs * 1000;
long ax = Math.abs(secs);
if (((ax | 1000) >>> 31 != 0)) {
if ((r / 1000) != secs) {
return (secs < 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
}
}
return r + nanos / 1000_000;
}
}
/**
* Time unit constants for conversion.
*/
private static final long HOURS_PER_DAY = 24L;
private static final long MINUTES_PER_HOUR = 60L;
private static final long SECONDS_PER_MINUTE = 60L;
private static final long SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
private static final long SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
private static final long MILLIS_PER_SECOND = 1000L;
private static final long MICROS_PER_SECOND = 1000_000L;
private static final long NANOS_PER_SECOND = 1000_000_000L;
private static final int NANOS_PER_MILLI = 1000_000;
private static final int NANOS_PER_MICRO = 1000;
// The epoch second of Instant.MIN.
private static final long MIN_SECOND = -31557014167219200L;
// The epoch second of Instant.MAX.
private static final long MAX_SECOND = 31556889864403199L;
/*
* Scale d by m, checking for overflow.
*/
private static long scale(long d, long m, long over) {
if (d > over) return Long.MAX_VALUE;
if (d < -over) return Long.MIN_VALUE;
return d * m;
}
/**
* Converts this {@code FileTime} object to an {@code Instant}.
*
* <p> The conversion creates an {@code Instant} that represents the
* same point on the time-line as this {@code FileTime}.
*
* <p> {@code FileTime} can store points on the time-line further in the
* future and further in the past than {@code Instant}. Conversion
* from such further time points saturates to {@link Instant.MIN} if
* earlier than {@code Instant.MIN} or {@link Instant.MAX} if later
* than {@code Instant.MAX}.
*
* @return an instant representing the same point on the time-line as
* this {@code FileTime} object
* @since 1.8
*/
public Instant toInstant() {
if (instant == null) {
long secs = 0L;
int nanos = 0;
switch (unit) {
case DAYS:
secs = scale(value, SECONDS_PER_DAY,
Long.MAX_VALUE/SECONDS_PER_DAY);
break;
case HOURS:
secs = scale(value, SECONDS_PER_HOUR,
Long.MAX_VALUE/SECONDS_PER_HOUR);
break;
case MINUTES:
secs = scale(value, SECONDS_PER_MINUTE,
Long.MAX_VALUE/SECONDS_PER_MINUTE);
break;
case SECONDS:
secs = value;
break;
case MILLISECONDS:
secs = Math.floorDiv(value, MILLIS_PER_SECOND);
nanos = (int)Math.floorMod(value, MILLIS_PER_SECOND)
* NANOS_PER_MILLI;
break;
case MICROSECONDS:
secs = Math.floorDiv(value, MICROS_PER_SECOND);
nanos = (int)Math.floorMod(value, MICROS_PER_SECOND)
* NANOS_PER_MICRO;
break;
case NANOSECONDS:
secs = Math.floorDiv(value, NANOS_PER_SECOND);
nanos = (int)Math.floorMod(value, NANOS_PER_SECOND);
break;
default : throw new AssertionError("Unit not handled");
}
if (secs <= MIN_SECOND)
instant = Instant.MIN;
else if (secs >= MAX_SECOND)
instant = Instant.MAX;
else
instant = Instant.ofEpochSecond(secs, nanos);
}
return instant;
}
/**
......@@ -176,8 +301,25 @@ public final class FileTime
*/
@Override
public int hashCode() {
// hashcode of days/nanos representation to satisfy contract with equals
return asDaysAndNanos().hashCode();
// hashcode of instant representation to satisfy contract with equals
return toInstant().hashCode();
}
private long toDays() {
if (unit != null) {
return unit.toDays(value);
} else {
return TimeUnit.SECONDS.toDays(toInstant().getEpochSecond());
}
}
private long toExcessNanos(long days) {
if (unit != null) {
return unit.toNanos(value - unit.convert(days, TimeUnit.DAYS));
} else {
return TimeUnit.SECONDS.toNanos(toInstant().getEpochSecond()
- TimeUnit.DAYS.toSeconds(days));
}
}
/**
......@@ -194,14 +336,52 @@ public final class FileTime
@Override
public int compareTo(FileTime other) {
// same granularity
if (unit == other.unit) {
return (value < other.value) ? -1 : (value == other.value ? 0 : 1);
if (unit != null && unit == other.unit) {
return Long.compare(value, other.value);
} else {
// compare using days/nanos representation when unit differs
return asDaysAndNanos().compareTo(other.asDaysAndNanos());
// compare using instant representation when unit differs
long secs = toInstant().getEpochSecond();
long secsOther = other.toInstant().getEpochSecond();
int cmp = Long.compare(secs, secsOther);
if (cmp != 0) {
return cmp;
}
cmp = Long.compare(toInstant().getNano(), other.toInstant().getNano());
if (cmp != 0) {
return cmp;
}
if (secs != MAX_SECOND && secs != MIN_SECOND) {
return 0;
}
// if both this and other's Instant reps are MIN/MAX,
// use daysSinceEpoch and nanosOfDays, which will not
// saturate during calculation.
long days = toDays();
long daysOther = other.toDays();
if (days == daysOther) {
return Long.compare(toExcessNanos(days), other.toExcessNanos(daysOther));
}
return Long.compare(days, daysOther);
}
}
// days in a 400 year cycle = 146097
// days in a 10,000 year cycle = 146097 * 25
// seconds per day = 86400
private static final long DAYS_PER_10000_YEARS = 146097L * 25L;
private static final long SECONDS_PER_10000_YEARS = 146097L * 25L * 86400L;
private static final long SECONDS_0000_TO_1970 = ((146097L * 5L) - (30L * 365L + 7L)) * 86400L;
// append year/month/day/hour/minute/second/nano with width and 0 padding
private StringBuilder append(StringBuilder sb, int w, int d) {
while (w > 0) {
sb.append((char)(d/w + '0'));
d = d % w;
w /= 10;
}
return sb;
}
/**
* Returns the string representation of this {@code FileTime}. The string
* is returned in the <a
......@@ -229,135 +409,67 @@ public final class FileTime
*/
@Override
public String toString() {
String v = valueAsString;
if (v == null) {
// overflow saturates to Long.MIN_VALUE or Long.MAX_VALUE so this
// limits the range:
// [-292275056-05-16T16:47:04.192Z,292278994-08-17T07:12:55.807Z]
long ms = toMillis();
// nothing to do when seconds/minutes/hours/days
String fractionAsString = "";
if (unit.compareTo(TimeUnit.SECONDS) < 0) {
long fraction = asDaysAndNanos().fractionOfSecondInNanos();
if (fraction != 0L) {
// fraction must be positive
if (fraction < 0L) {
final long MAX_FRACTION_PLUS_1 = 1000L * 1000L * 1000L;
fraction += MAX_FRACTION_PLUS_1;
if (ms != Long.MIN_VALUE) ms--;
}
// convert to String, adding leading zeros as required and
// stripping any trailing zeros
String s = Long.toString(fraction);
int len = s.length();
int width = 9 - len;
StringBuilder sb = new StringBuilder(".");
while (width-- > 0) {
sb.append('0');
}
if (s.charAt(len-1) == '0') {
// drop trailing zeros
len--;
while (s.charAt(len-1) == '0')
len--;
sb.append(s.substring(0, len));
} else {
sb.append(s);
}
fractionAsString = sb.toString();
}
if (valueAsString == null) {
long secs = 0L;
int nanos = 0;
if (instant == null && unit.compareTo(TimeUnit.SECONDS) >= 0) {
secs = unit.toSeconds(value);
} else {
secs = toInstant().getEpochSecond();
nanos = toInstant().getNano();
}
// create calendar to use with formatter.
GregorianCalendar cal =
new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.ROOT);
if (value < 0L)
cal.setGregorianChange(new Date(Long.MIN_VALUE));
cal.setTimeInMillis(ms);
// years are negative before common era
String sign = (cal.get(Calendar.ERA) == GregorianCalendar.BC) ? "-" : "";
// [-]YYYY-MM-DDThh:mm:ss[.s]Z
v = new Formatter(Locale.ROOT)
.format("%s%tFT%tR:%tS%sZ", sign, cal, cal, cal, fractionAsString)
.toString();
valueAsString = v;
}
return v;
}
/**
* Represents a FileTime's value as two longs: the number of days since
* the epoch, and the excess (in nanoseconds). This is used for comparing
* values with different units of granularity.
*/
private static class DaysAndNanos implements Comparable<DaysAndNanos> {
// constants for conversion
private static final long C0 = 1L;
private static final long C1 = C0 * 24L;
private static final long C2 = C1 * 60L;
private static final long C3 = C2 * 60L;
private static final long C4 = C3 * 1000L;
private static final long C5 = C4 * 1000L;
private static final long C6 = C5 * 1000L;
/**
* The value (in days) since the epoch; can be negative.
*/
private final long days;
/**
* The excess (in nanoseconds); can be negative if days &lt;= 0.
*/
private final long excessNanos;
/**
* Initializes a new instance of this class.
*/
DaysAndNanos(long value, TimeUnit unit) {
long scale;
switch (unit) {
case DAYS : scale = C0; break;
case HOURS : scale = C1; break;
case MINUTES : scale = C2; break;
case SECONDS : scale = C3; break;
case MILLISECONDS : scale = C4; break;
case MICROSECONDS : scale = C5; break;
case NANOSECONDS : scale = C6; break;
default : throw new AssertionError("Unit not handled");
LocalDateTime ldt;
int year = 0;
if (secs >= -SECONDS_0000_TO_1970) {
// current era
long zeroSecs = secs - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970;
long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1;
long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS);
ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC);
year = ldt.getYear() + (int)hi * 10000;
} else {
// before current era
long zeroSecs = secs + SECONDS_0000_TO_1970;
long hi = zeroSecs / SECONDS_PER_10000_YEARS;
long lo = zeroSecs % SECONDS_PER_10000_YEARS;
ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC);
year = ldt.getYear() + (int)hi * 10000;
}
this.days = unit.toDays(value);
this.excessNanos = unit.toNanos(value - (this.days * scale));
}
/**
* Returns the fraction of a second, in nanoseconds.
*/
long fractionOfSecondInNanos() {
return excessNanos % (1000L * 1000L * 1000L);
}
@Override
public boolean equals(Object obj) {
return (obj instanceof DaysAndNanos) ?
compareTo((DaysAndNanos)obj) == 0 : false;
}
@Override
public int hashCode() {
return (int)(days ^ (days >>> 32) ^
excessNanos ^ (excessNanos >>> 32));
}
@Override
public int compareTo(DaysAndNanos other) {
if (this.days != other.days)
return (this.days < other.days) ? -1 : 1;
return (this.excessNanos < other.excessNanos) ? -1 :
(this.excessNanos == other.excessNanos) ? 0 : 1;
if (year <= 0) {
year = year - 1;
}
int fraction = ldt.getNano();
StringBuilder sb = new StringBuilder(64);
sb.append(year < 0 ? "-" : "");
year = Math.abs(year);
if (year < 10000) {
append(sb, 1000, Math.abs(year));
} else {
sb.append(String.valueOf(year));
}
sb.append('-');
append(sb, 10, ldt.getMonthValue());
sb.append('-');
append(sb, 10, ldt.getDayOfMonth());
sb.append('T');
append(sb, 10, ldt.getHour());
sb.append(':');
append(sb, 10, ldt.getMinute());
sb.append(':');
append(sb, 10, ldt.getSecond());
if (fraction != 0) {
sb.append('.');
// adding leading zeros and stripping any trailing zeros
int w = 100_000_000;
while (fraction % 10 == 0) {
fraction /= 10;
w /= 10;
}
append(sb, w, fraction);
}
sb.append('Z');
valueAsString = sb.toString();
}
return valueAsString;
}
}
......@@ -61,13 +61,13 @@
*/
package java.time;
import java.time.temporal.UnsupportedTemporalTypeException;
import static java.time.temporal.ChronoField.DAY_OF_WEEK;
import static java.time.temporal.ChronoUnit.DAYS;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
......@@ -259,7 +259,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* <p>
* If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
* range of the day-of-week, from 1 to 7, will be returned.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -269,6 +269,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override
public ValueRange range(TemporalField field) {
......@@ -288,7 +289,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* <p>
* If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
* value of the day-of-week, from 1 to 7, will be returned.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -297,7 +298,10 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
*
* @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 a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -317,7 +321,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* <p>
* If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
* value of the day-of-week, from 1 to 7, will be returned.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -327,6 +331,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -334,7 +339,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
if (field == DAY_OF_WEEK) {
return getValue();
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.getFrom(this);
}
......@@ -393,7 +398,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.precision()) {
if (query == TemporalQuery.precision()) {
return (R) DAYS;
}
return TemporalAccessor.super.query(query);
......@@ -409,8 +414,8 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* passing {@link ChronoField#DAY_OF_WEEK} as the field.
* Note that this adjusts forwards or backwards within a Monday to Sunday week.
* See {@link WeekFields#dayOfWeek} for localized week start days.
* See {@link java.time.temporal.Adjusters Adjusters} for other adjusters
* with more control, such as {@code next(MONDAY)}.
* See {@code TemporalAdjuster} for other adjusters with more control,
* such as {@code next(MONDAY)}.
* <p>
* In most cases, it is clearer to reverse the calling pattern by using
* {@link Temporal#with(TemporalAdjuster)}:
......
......@@ -85,6 +85,7 @@ import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
......@@ -302,31 +303,32 @@ public final class Duration
//-----------------------------------------------------------------------
/**
* Obtains a {@code Duration} representing the duration between two instants.
* <p>
* 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.
* Obtains an instance of {@code Duration} from a temporal amount.
* <p>
* This obtains a duration based on the specified amount.
* A {@code TemporalAmount} represents an amount of time, which may be
* date-based or time-based, which this factory extracts to a duration.
* <p>
* The conversion loops around the set of units from the amount and uses
* the {@linkplain TemporalUnit#getDuration() duration} of the unit to
* calculate the total {@code Duration}.
* Only a subset of units are accepted by this method. The unit must either
* have an {@linkplain TemporalUnit#isDurationEstimated() exact duration}
* or be {@link ChronoUnit#DAYS} which is treated as 24 hours.
* If any other units are found then an exception is thrown.
*
* @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}
* @param amount the temporal amount to convert, not null
* @return the equivalent duration, not null
* @throws DateTimeException if unable to convert to a {@code Duration}
* @throws ArithmeticException if numeric overflow occurs
*/
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;
public static Duration from(TemporalAmount amount) {
Objects.requireNonNull(amount, "amount");
Duration duration = ZERO;
for (TemporalUnit unit : amount.getUnits()) {
duration = duration.plus(amount.get(unit), unit);
}
return ofSeconds(secs, nanos);
return duration;
}
//-----------------------------------------------------------------------
......@@ -360,14 +362,14 @@ public final class Duration
* <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"
* "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
......@@ -437,6 +439,44 @@ public final class Duration
return ofSeconds(seconds, nanos);
}
//-----------------------------------------------------------------------
/**
* Obtains a {@code Duration} representing the duration between two instants.
* <p>
* This calculates the duration between two temporal objects of the same type.
* The specified temporal objects must support the {@link ChronoUnit#SECONDS SECONDS} unit.
* For full accuracy, either the {@link ChronoUnit#NANOS NANOS} unit or the
* {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field should be supported.
* <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 DateTimeException if the seconds between the temporals cannot be obtained
* @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration}
*/
public static Duration between(Temporal startInclusive, Temporal endExclusive) {
try {
return ofNanos(startInclusive.periodUntil(endExclusive, NANOS));
} catch (DateTimeException | ArithmeticException ex) {
long secs = startInclusive.periodUntil(endExclusive, SECONDS);
long nanos;
try {
nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND);
if (secs > 0 && nanos < 0) {
secs++;
} else if (secs < 0 && nanos > 0) {
secs--;
}
} catch (DateTimeException ex2) {
nanos = 0;
}
return ofSeconds(secs, nanos);
}
}
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Duration} using seconds and nanoseconds.
......@@ -474,6 +514,7 @@ public final class Duration
* @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
* @throws UnsupportedTemporalTypeException if the unit is not supported
*/
@Override
public long get(TemporalUnit unit) {
......@@ -482,7 +523,7 @@ public final class Duration
} else if (unit == NANOS) {
return nanos;
} else {
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
}
......@@ -637,6 +678,7 @@ public final class Duration
* @param amountToAdd the amount of the period, measured in terms of the unit, positive or negative
* @param unit the unit that the period is measured in, must have an exact duration, not null
* @return a {@code Duration} based on this duration with the specified duration added, not null
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
public Duration plus(long amountToAdd, TemporalUnit unit) {
......@@ -645,7 +687,7 @@ public final class Duration
return plus(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY), 0);
}
if (unit.isDurationEstimated()) {
throw new DateTimeException("Unit must not have an estimated duration");
throw new UnsupportedTemporalTypeException("Unit must not have an estimated duration");
}
if (amountToAdd == 0) {
return this;
......@@ -1130,9 +1172,9 @@ public final class Duration
* @throws ArithmeticException if numeric overflow occurs
*/
public long toNanos() {
long millis = Math.multiplyExact(seconds, NANOS_PER_SECOND);
millis = Math.addExact(millis, nanos);
return millis;
long totalNanos = Math.multiplyExact(seconds, NANOS_PER_SECOND);
totalNanos = Math.addExact(totalNanos, nanos);
return totalNanos;
}
//-----------------------------------------------------------------------
......@@ -1199,10 +1241,10 @@ public final class Duration
* <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"
* "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}.
......
......@@ -81,7 +81,6 @@ import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
......@@ -89,6 +88,7 @@ import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.Objects;
......@@ -148,6 +148,8 @@ import java.util.Objects;
* <li>other times during the day will be broadly in line with the agreed international civil time</li>
* <li>the day will be divided into exactly 86400 subdivisions, referred to as "seconds"</li>
* <li>the Java "second" may differ from an SI second</li>
* <li>a well-defined algorithm must be specified to map each second in the accurate agreed
* international civil time to each "second" in this time-scale</li>
* </ul><p>
* Agreed international civil time is the base time-scale agreed by international convention,
* which in 2012 is UTC (with leap-seconds).
......@@ -155,6 +157,14 @@ import java.util.Objects;
* In 2012, the definition of the Java time-scale is the same as UTC for all days except
* those where a leap-second occurs. On days where a leap-second does occur, the time-scale
* effectively eliminates the leap-second, maintaining the fiction of 86400 seconds in the day.
* The approved well-defined algorithm to eliminate leap-seconds is specified as
* <a href="http://www.cl.cam.ac.uk/~mgk25/time/utc-sls/">UTC-SLS</a>.
* <p>
* UTC-SLS is a simple algorithm that smoothes the leap-second over the last 1000 seconds of
* the day, making each of the last 1000 seconds 1/1000th longer or shorter than an SI second.
* Implementations built on an accurate leap-second aware time source should use UTC-SLS.
* Use of a different algorithm risks confusion and misinterpretation of instants around a
* leap-second and is discouraged.
* <p>
* The main benefit of always dividing the day into 86400 subdivisions is that it matches the
* expectations of most users of the API. The alternative is to force every user to understand
......@@ -163,16 +173,10 @@ import java.util.Objects;
* Most applications also do not have a problem with a second being a very small amount longer or
* shorter than a real SI second during a leap-second.
* <p>
* If an application does have access to an accurate clock that reports leap-seconds, then the
* recommended technique to implement the Java time-scale is to use the UTC-SLS convention.
* <a href="http://www.cl.cam.ac.uk/~mgk25/time/utc-sls/">UTC-SLS</a> effectively smoothes the
* leap-second over the last 1000 seconds of the day, making each of the last 1000 "seconds"
* 1/1000th longer or shorter than a real SI second.
* <p>
* One final problem is the definition of the agreed international civil time before the
* introduction of modern UTC in 1972. This includes the Java epoch of {@code 1970-01-01}.
* It is intended that instants before 1972 be interpreted based on the solar day divided
* into 86400 subdivisions.
* into 86400 subdivisions, as per the principles of UT1.
* <p>
* The Java time-scale is used for all date-time classes.
* This includes {@code Instant}, {@code LocalDate}, {@code LocalTime}, {@code OffsetDateTime},
......@@ -210,7 +214,7 @@ public final class Instant
*/
public static final Instant MIN = Instant.ofEpochSecond(MIN_SECOND, 0);
/**
* The minimum supported {@code Instant}, '-1000000000-01-01T00:00Z'.
* The maximum supported {@code Instant}, '1000000000-12-31T23:59:59.999999999Z'.
* This could be used by an application as a "far future" instant.
* <p>
* This is one year later than the maximum {@code LocalDateTime}.
......@@ -292,9 +296,9 @@ public final class Instant
* to ensure that the stored nanosecond is in the range 0 to 999,999,999.
* For example, the following will result in the exactly the same instant:
* <pre>
* Instant.ofSeconds(3, 1);
* Instant.ofSeconds(4, -999_999_999);
* Instant.ofSeconds(2, 1000_000_001);
* Instant.ofEpochSecond(3, 1);
* Instant.ofEpochSecond(4, -999_999_999);
* Instant.ofEpochSecond(2, 1000_000_001);
* </pre>
*
* @param epochSecond the number of seconds from 1970-01-01T00:00:00Z
......@@ -441,7 +445,7 @@ public final class Instant
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -451,6 +455,7 @@ public final class Instant
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override // override for Javadoc
public ValueRange range(TemporalField field) {
......@@ -469,7 +474,7 @@ public final class Instant
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this date-time, except {@code INSTANT_SECONDS} which is too
* large to fit in an {@code int} and throws a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -478,7 +483,10 @@ public final class Instant
*
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override // override for Javadoc and performance
......@@ -490,7 +498,7 @@ public final class Instant
case MILLI_OF_SECOND: return nanos / 1000_000;
case INSTANT_SECONDS: INSTANT_SECONDS.checkValidIntValue(seconds);
}
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return range(field).checkValidIntValue(field.getFrom(this), field);
}
......@@ -505,7 +513,7 @@ public final class Instant
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this date-time.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -515,6 +523,7 @@ public final class Instant
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -526,7 +535,7 @@ public final class Instant
case MILLI_OF_SECOND: return nanos / 1000_000;
case INSTANT_SECONDS: return seconds;
}
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.getFrom(this);
}
......@@ -610,7 +619,7 @@ public final class Instant
* In all cases, if the new value is outside the valid range of values for the field
* then a {@code DateTimeException} will be thrown.
* <p>
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
......@@ -623,6 +632,7 @@ public final class Instant
* @param newValue the new value of the field in the result
* @return an {@code Instant} based on {@code this} with the specified field set, not null
* @throws DateTimeException if the field cannot be set
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -642,7 +652,7 @@ public final class Instant
case NANO_OF_SECOND: return (newValue != nanos ? create(seconds, (int) newValue) : this);
case INSTANT_SECONDS: return (newValue != seconds ? create(newValue, nanos) : this);
}
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.adjustInto(this, newValue);
}
......@@ -668,6 +678,7 @@ public final class Instant
* @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
* @throws UnsupportedTemporalTypeException if the unit is not supported
*/
public Instant truncatedTo(TemporalUnit unit) {
if (unit == ChronoUnit.NANOS) {
......@@ -675,11 +686,11 @@ public final class Instant
}
Duration unitDur = unit.getDuration();
if (unitDur.getSeconds() > LocalTime.SECONDS_PER_DAY) {
throw new DateTimeException("Unit is too large to be used for truncation");
throw new UnsupportedTemporalTypeException("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");
throw new UnsupportedTemporalTypeException("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;
......@@ -754,7 +765,7 @@ public final class Instant
* multiplied by 86,400 (24 hours).
* </ul>
* <p>
* All other {@code ChronoUnit} instances will throw a {@code DateTimeException}.
* All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
......@@ -767,6 +778,7 @@ public final class Instant
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -782,7 +794,7 @@ public final class Instant
case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2));
case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY));
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return unit.addTo(this, amountToAdd);
}
......@@ -894,6 +906,7 @@ public final class Instant
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -975,11 +988,12 @@ public final class Instant
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.precision()) {
if (query == TemporalQuery.precision()) {
return (R) NANOS;
}
// inline TemporalAccessor.super.query(query) as an optimization
if (query == Queries.chronology() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
if (query == TemporalQuery.chronology() || query == TemporalQuery.zoneId() ||
query == TemporalQuery.zone() || query == TemporalQuery.offset()) {
return null;
}
return query.queryFrom(this);
......@@ -1028,14 +1042,15 @@ public final class Instant
* For example, the period in days between two dates can be calculated
* using {@code startInstant.periodUntil(endInstant, SECONDS)}.
* <p>
* This method operates in association with {@link TemporalUnit#between}.
* The result of this method is a {@code long} representing the amount of
* the specified unit. By contrast, the result of {@code between} is an
* object that can be used directly in addition/subtraction:
* 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, SECONDS); // this method
* dateTime.plus(SECONDS.between(start, end)); // use in plus/minus
* // these two lines are equivalent
* amount = start.periodUntil(end, SECONDS);
* amount = SECONDS.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},
......@@ -1053,6 +1068,7 @@ public final class Instant
* @param unit the unit to measure the period in, not null
* @return the amount of the period between this date and the end date
* @throws DateTimeException if the period cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1074,18 +1090,26 @@ public final class Instant
case HALF_DAYS: return secondsUntil(end) / (12 * SECONDS_PER_HOUR);
case DAYS: return secondsUntil(end) / (SECONDS_PER_DAY);
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return unit.between(this, endInstant);
}
private long nanosUntil(Instant end) {
long secs = Math.multiplyExact(secondsUntil(end), NANOS_PER_SECOND);
return Math.addExact(secs, end.nanos - nanos);
long secsDiff = Math.subtractExact(end.seconds, seconds);
long totalNanos = Math.multiplyExact(secsDiff, NANOS_PER_SECOND);
return Math.addExact(totalNanos, end.nanos - nanos);
}
private long secondsUntil(Instant end) {
return Math.subtractExact(end.seconds, seconds);
long secsDiff = Math.subtractExact(end.seconds, seconds);
long nanosDiff = end.nanos - nanos;
if (secsDiff > 0 && nanosDiff < 0) {
secsDiff--;
} else if (secsDiff < 0 && nanosDiff > 0) {
secsDiff++;
}
return secsDiff;
}
//-----------------------------------------------------------------------
......
......@@ -79,12 +79,10 @@ 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.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;
......@@ -92,6 +90,7 @@ import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.time.zone.ZoneRules;
import java.util.Objects;
......@@ -546,7 +545,7 @@ public final class LocalDateTime
* <li>{@code ALIGNED_WEEK_OF_MONTH}
* <li>{@code ALIGNED_WEEK_OF_YEAR}
* <li>{@code MONTH_OF_YEAR}
* <li>{@code EPOCH_MONTH}
* <li>{@code PROLEPTIC_MONTH}
* <li>{@code YEAR_OF_ERA}
* <li>{@code YEAR}
* <li>{@code ERA}
......@@ -565,7 +564,7 @@ public final class LocalDateTime
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
ChronoField f = (ChronoField) field;
return f.isDateField() || f.isTimeField();
return f.isDateBased() || f.isTimeBased();
}
return field != null && field.isSupportedBy(this);
}
......@@ -581,7 +580,7 @@ public final class LocalDateTime
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -591,12 +590,13 @@ public final class LocalDateTime
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override
public ValueRange range(TemporalField field) {
if (field instanceof ChronoField) {
ChronoField f = (ChronoField) field;
return (f.isTimeField() ? time.range(field) : date.range(field));
return (f.isTimeBased() ? time.range(field) : date.range(field));
}
return field.rangeRefinedBy(this);
}
......@@ -612,9 +612,9 @@ public final class LocalDateTime
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
* {@code EPOCH_DAY} and {@code EPOCH_MONTH} which are too large to fit in
* {@code EPOCH_DAY} and {@code PROLEPTIC_MONTH} which are too large to fit in
* an {@code int} and throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -623,14 +623,17 @@ public final class LocalDateTime
*
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public int get(TemporalField field) {
if (field instanceof ChronoField) {
ChronoField f = (ChronoField) field;
return (f.isTimeField() ? time.get(field) : date.get(field));
return (f.isTimeBased() ? time.get(field) : date.get(field));
}
return ChronoLocalDateTime.super.get(field);
}
......@@ -645,7 +648,7 @@ public final class LocalDateTime
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this date-time.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -655,13 +658,14 @@ public final class LocalDateTime
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long getLong(TemporalField field) {
if (field instanceof ChronoField) {
ChronoField f = (ChronoField) field;
return (f.isTimeField() ? time.getLong(field) : date.getLong(field));
return (f.isTimeBased() ? time.getLong(field) : date.getLong(field));
}
return field.getFrom(this);
}
......@@ -822,7 +826,7 @@ public final class LocalDateTime
* <p>
* A simple adjuster might simply set the one of the fields, such as the year field.
* A more complex adjuster might set the date to the last day of the month.
* A selection of common adjustments is provided in {@link java.time.temporal.Adjusters}.
* A selection of common adjustments is provided in {@link TemporalAdjuster}.
* These include finding the "last day of the month" and "next Wednesday".
* Key date-time classes also implement the {@code TemporalAdjuster} interface,
* such as {@link Month} and {@link java.time.MonthDay MonthDay}.
......@@ -886,7 +890,7 @@ public final class LocalDateTime
* The {@link #isSupported(TemporalField) supported fields} will behave as per
* the matching method on {@link LocalDate#with(TemporalField, long) LocalDate}
* or {@link LocalTime#with(TemporalField, long) LocalTime}.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
......@@ -899,13 +903,14 @@ public final class LocalDateTime
* @param newValue the new value of the field in the result
* @return a {@code LocalDateTime} based on {@code this} with the specified field set, not null
* @throws DateTimeException if the field cannot be set
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public LocalDateTime with(TemporalField field, long newValue) {
if (field instanceof ChronoField) {
ChronoField f = (ChronoField) field;
if (f.isTimeField()) {
if (f.isTimeBased()) {
return with(date, time.with(field, newValue));
} else {
return with(date.with(field, newValue), time);
......@@ -1052,6 +1057,7 @@ public final class LocalDateTime
* @param unit the unit to truncate to, not null
* @return a {@code LocalDateTime} based on this date-time with the time truncated, not null
* @throws DateTimeException if unable to truncate
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
public LocalDateTime truncatedTo(TemporalUnit unit) {
return with(date, time.truncatedTo(unit));
......@@ -1106,6 +1112,7 @@ public final class LocalDateTime
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1312,6 +1319,7 @@ public final class LocalDateTime
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1517,7 +1525,7 @@ public final class LocalDateTime
@SuppressWarnings("unchecked")
@Override // override for Javadoc
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.localDate()) {
if (query == TemporalQuery.localDate()) {
return (R) date;
}
return ChronoLocalDateTime.super.query(query);
......@@ -1597,6 +1605,7 @@ public final class LocalDateTime
* @param unit the unit to measure the period in, not null
* @return the amount of the period between this date-time and the end date-time
* @throws DateTimeException if the period cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1610,31 +1619,79 @@ public final class LocalDateTime
ChronoUnit f = (ChronoUnit) unit;
if (f.isTimeUnit()) {
long amount = date.daysUntil(end.date);
if (amount == 0) {
return time.periodUntil(end.time, unit);
}
long timePart = end.time.toNanoOfDay() - time.toNanoOfDay();
if (amount > 0) {
amount--; // safe
timePart += NANOS_PER_DAY; // safe
} else {
amount++; // safe
timePart -= NANOS_PER_DAY; // safe
}
switch (f) {
case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break;
case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break;
case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break;
case SECONDS: amount = Math.multiplyExact(amount, SECONDS_PER_DAY); break;
case MINUTES: amount = Math.multiplyExact(amount, MINUTES_PER_DAY); break;
case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
case NANOS:
amount = Math.multiplyExact(amount, NANOS_PER_DAY);
break;
case MICROS:
amount = Math.multiplyExact(amount, MICROS_PER_DAY);
timePart = timePart / 1000;
break;
case MILLIS:
amount = Math.multiplyExact(amount, MILLIS_PER_DAY);
timePart = timePart / 1_000_000;
break;
case SECONDS:
amount = Math.multiplyExact(amount, SECONDS_PER_DAY);
timePart = timePart / NANOS_PER_SECOND;
break;
case MINUTES:
amount = Math.multiplyExact(amount, MINUTES_PER_DAY);
timePart = timePart / NANOS_PER_MINUTE;
break;
case HOURS:
amount = Math.multiplyExact(amount, HOURS_PER_DAY);
timePart = timePart / NANOS_PER_HOUR;
break;
case HALF_DAYS:
amount = Math.multiplyExact(amount, 2);
timePart = timePart / (NANOS_PER_HOUR * 12);
break;
}
return Math.addExact(amount, time.periodUntil(end.time, unit));
return Math.addExact(amount, timePart);
}
LocalDate endDate = end.date;
if (end.time.isBefore(time)) {
if (endDate.isAfter(date) && end.time.isBefore(time)) {
endDate = endDate.minusDays(1);
} else if (endDate.isBefore(date) && end.time.isAfter(time)) {
endDate = endDate.plusDays(1);
}
return date.periodUntil(endDate, unit);
}
return unit.between(this, endDateTime);
}
/**
* Formats this date-time using the specified formatter.
* <p>
* This date-time will be passed to the formatter to produce a string.
*
* @param formatter the formatter to use, not null
* @return the formatted date-time string, not null
* @throws DateTimeException if an error occurs during printing
*/
@Override // override for Javadoc and performance
public String format(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Combines this time with a date to create an {@code OffsetTime}.
* Combines this date-time with an offset to create an {@code OffsetDateTime}.
* <p>
* This returns an {@code OffsetTime} formed from this time at the specified offset.
* This returns an {@code OffsetDateTime} formed from this date-time at the specified offset.
* All possible combinations of date-time and offset are valid.
*
* @param offset the offset to combine with, not null
......@@ -1645,7 +1702,7 @@ public final class LocalDateTime
}
/**
* Combines this time with a time-zone to create a {@code ZonedDateTime}.
* Combines this date-time with a time-zone to create a {@code ZonedDateTime}.
* <p>
* 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.
......@@ -1725,7 +1782,7 @@ public final class LocalDateTime
* This method only considers the position of the two date-times on the local time-line.
* It does not take into account the chronology, or calendar system.
* This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
* but is the same approach as {@link #DATE_TIME_COMPARATOR}.
* but is the same approach as {@link ChronoLocalDateTime#timeLineOrder()}.
*
* @param other the other date-time to compare to, not null
* @return true if this date-time is after the specified date-time
......@@ -1754,7 +1811,7 @@ public final class LocalDateTime
* This method only considers the position of the two date-times on the local time-line.
* It does not take into account the chronology, or calendar system.
* This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
* but is the same approach as {@link #DATE_TIME_COMPARATOR}.
* but is the same approach as {@link ChronoLocalDateTime#timeLineOrder()}.
*
* @param other the other date-time to compare to, not null
* @return true if this date-time is before the specified date-time
......@@ -1783,7 +1840,7 @@ public final class LocalDateTime
* This method only considers the position of the two date-times on the local time-line.
* It does not take into account the chronology, or calendar system.
* This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
* but is the same approach as {@link #DATE_TIME_COMPARATOR}.
* but is the same approach as {@link ChronoLocalDateTime#timeLineOrder()}.
*
* @param other the other date-time to compare to, not null
* @return true if this date-time is equal to the specified date-time
......@@ -1834,11 +1891,11 @@ public final class LocalDateTime
* <p>
* The output will be one of the following ISO-8601 formats:
* <p><ul>
* <li>{@code yyyy-MM-dd'T'HH:mm}</li>
* <li>{@code yyyy-MM-dd'T'HH:mm:ss}</li>
* <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSS}</li>
* <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSS}</li>
* <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS}</li>
* <li>{@code uuuu-MM-dd'T'HH:mm}</li>
* <li>{@code uuuu-MM-dd'T'HH:mm:ss}</li>
* <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSS}</li>
* <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSS}</li>
* <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS}</li>
* </ul><p>
* The format used will be the shortest that outputs the full value of
* the time where the omitted parts are implied to be zero.
......@@ -1850,21 +1907,6 @@ public final class LocalDateTime
return date.toString() + 'T' + time.toString();
}
/**
* Outputs this date-time as a {@code String} using the formatter.
* <p>
* This date-time will be passed to the formatter
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted date-time string, not null
* @throws DateTimeException if an error occurs during printing
*/
@Override // override for Javadoc
public String toString(DateTimeFormatter formatter) {
return ChronoLocalDateTime.super.toString(formatter);
}
//-----------------------------------------------------------------------
/**
* Writes the object using a
......
......@@ -80,7 +80,6 @@ import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
......@@ -88,6 +87,7 @@ import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.Objects;
......@@ -383,7 +383,7 @@ public final class LocalTime
* 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 uses the {@link Queries#localTime()} query, which relies
* The conversion uses the {@link TemporalQuery#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}
......@@ -394,7 +394,7 @@ public final class LocalTime
* @throws DateTimeException if unable to convert to a {@code LocalTime}
*/
public static LocalTime from(TemporalAccessor temporal) {
LocalTime time = temporal.query(Queries.localTime());
LocalTime time = temporal.query(TemporalQuery.localTime());
if (time == null) {
throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass());
}
......@@ -505,7 +505,7 @@ public final class LocalTime
@Override
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
return ((ChronoField) field).isTimeField();
return field.isTimeBased();
}
return field != null && field.isSupportedBy(this);
}
......@@ -521,7 +521,7 @@ public final class LocalTime
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -531,6 +531,7 @@ public final class LocalTime
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override // override for Javadoc
public ValueRange range(TemporalField field) {
......@@ -549,7 +550,7 @@ public final class LocalTime
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY}
* which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -558,7 +559,10 @@ public final class LocalTime
*
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override // override for Javadoc and performance
......@@ -579,7 +583,7 @@ public final class LocalTime
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this time.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -589,6 +593,7 @@ public final class LocalTime
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -608,9 +613,9 @@ public final class LocalTime
private int get0(TemporalField field) {
switch ((ChronoField) field) {
case NANO_OF_SECOND: return nano;
case NANO_OF_DAY: throw new DateTimeException("Field too large for an int: " + field);
case NANO_OF_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'NanoOfDay' for get() method, use getLong() instead");
case MICRO_OF_SECOND: return nano / 1000;
case MICRO_OF_DAY: throw new DateTimeException("Field too large for an int: " + field);
case MICRO_OF_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'MicroOfDay' for get() method, use getLong() instead");
case MILLI_OF_SECOND: return nano / 1000_000;
case MILLI_OF_DAY: return (int) (toNanoOfDay() / 1000_000);
case SECOND_OF_MINUTE: return second;
......@@ -623,7 +628,7 @@ public final class LocalTime
case CLOCK_HOUR_OF_DAY: return (hour == 0 ? 24 : hour);
case AMPM_OF_DAY: return hour / 12;
}
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
//-----------------------------------------------------------------------
......@@ -760,7 +765,7 @@ public final class LocalTime
* In all cases, if the new value is outside the valid range of values for the field
* then a {@code DateTimeException} will be thrown.
* <p>
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
......@@ -773,6 +778,7 @@ public final class LocalTime
* @param newValue the new value of the field in the result
* @return a {@code LocalTime} based on {@code this} with the specified field set, not null
* @throws DateTimeException if the field cannot be set
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -797,7 +803,7 @@ public final class LocalTime
case CLOCK_HOUR_OF_DAY: return withHour((int) (newValue == 24 ? 0 : newValue));
case AMPM_OF_DAY: return plusHours((newValue - (hour / 12)) * 12);
}
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.adjustInto(this, newValue);
}
......@@ -890,6 +896,7 @@ public final class LocalTime
* @param unit the unit to truncate to, not null
* @return a {@code LocalTime} based on this time with the time truncated, not null
* @throws DateTimeException if unable to truncate
* @throws UnsupportedTemporalTypeException if the unit is not supported
*/
public LocalTime truncatedTo(TemporalUnit unit) {
if (unit == ChronoUnit.NANOS) {
......@@ -897,11 +904,11 @@ public final class LocalTime
}
Duration unitDur = unit.getDuration();
if (unitDur.getSeconds() > SECONDS_PER_DAY) {
throw new DateTimeException("Unit is too large to be used for truncation");
throw new UnsupportedTemporalTypeException("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");
throw new UnsupportedTemporalTypeException("Unit must divide into a standard day without remainder");
}
long nod = toNanoOfDay();
return ofNanoOfDay((nod / dur) * dur);
......@@ -972,7 +979,7 @@ public final class LocalTime
* This returns {@code this} time.
* </ul>
* <p>
* All other {@code ChronoUnit} instances will throw a {@code DateTimeException}.
* All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
......@@ -985,6 +992,7 @@ public final class LocalTime
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1001,7 +1009,7 @@ public final class LocalTime
case HALF_DAYS: return plusHours((amountToAdd % 2) * 12);
case DAYS: return this;
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return unit.addTo(this, amountToAdd);
}
......@@ -1147,6 +1155,7 @@ public final class LocalTime
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1237,13 +1246,14 @@ public final class LocalTime
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.chronology() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
if (query == TemporalQuery.chronology() || query == TemporalQuery.zoneId() ||
query == TemporalQuery.zone() || query == TemporalQuery.offset()) {
return null;
} else if (query == Queries.localTime()) {
} else if (query == TemporalQuery.localTime()) {
return (R) this;
} else if (query == Queries.localDate()) {
} else if (query == TemporalQuery.localDate()) {
return null;
} else if (query == Queries.precision()) {
} else if (query == TemporalQuery.precision()) {
return (R) NANOS;
}
// inline TemporalAccessor.super.query(query) as an optimization
......@@ -1322,6 +1332,7 @@ public final class LocalTime
* @param unit the unit to measure the period in, not null
* @return the amount of the period between this time and the end time
* @throws DateTimeException if the period cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1342,11 +1353,25 @@ public final class LocalTime
case HOURS: return nanosUntil / NANOS_PER_HOUR;
case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return unit.between(this, endTime);
}
/**
* Formats this time using the specified formatter.
* <p>
* This time will be passed to the formatter to produce a string.
*
* @param formatter the formatter to use, not null
* @return the formatted time string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String format(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Combines this time with a date to create a {@code LocalDateTime}.
......@@ -1362,7 +1387,7 @@ public final class LocalTime
}
/**
* Combines this time with a date to create an {@code OffsetTime}.
* Combines this time with an offset to create an {@code OffsetTime}.
* <p>
* This returns an {@code OffsetTime} formed from this time at the specified offset.
* All possible combinations of time and offset are valid.
......@@ -1533,21 +1558,6 @@ public final class LocalTime
return buf.toString();
}
/**
* Outputs this time as a {@code String} using the formatter.
* <p>
* This time will be passed to the formatter
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted time string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Writes the object using a
......
......@@ -61,6 +61,7 @@
*/
package java.time;
import java.time.temporal.UnsupportedTemporalTypeException;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoUnit.MONTHS;
......@@ -69,7 +70,6 @@ import java.time.chrono.IsoChronology;
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;
......@@ -290,7 +290,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* <p>
* If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
* range of the month-of-year, from 1 to 12, will be returned.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -300,6 +300,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override
public ValueRange range(TemporalField field) {
......@@ -319,7 +320,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* <p>
* If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
* value of the month-of-year, from 1 to 12, will be returned.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -328,7 +329,10 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
*
* @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 a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -348,7 +352,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* <p>
* If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
* value of the month-of-year, from 1 to 12, will be returned.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -358,6 +362,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -365,7 +370,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
if (field == MONTH_OF_YEAR) {
return getValue();
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.getFrom(this);
}
......@@ -554,9 +559,9 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.chronology()) {
if (query == TemporalQuery.chronology()) {
return (R) IsoChronology.INSTANCE;
} else if (query == Queries.precision()) {
} else if (query == TemporalQuery.precision()) {
return (R) MONTHS;
}
return TemporalAccessor.super.query(query);
......
......@@ -76,12 +76,12 @@ 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.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.Objects;
......@@ -354,7 +354,7 @@ public final class MonthDay
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -364,6 +364,7 @@ public final class MonthDay
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override
public ValueRange range(TemporalField field) {
......@@ -386,7 +387,7 @@ public final class MonthDay
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this month-day.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -395,7 +396,10 @@ public final class MonthDay
*
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override // override for Javadoc
......@@ -413,7 +417,7 @@ public final class MonthDay
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this month-day.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -423,6 +427,7 @@ public final class MonthDay
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -433,7 +438,7 @@ public final class MonthDay
case DAY_OF_MONTH: return day;
case MONTH_OF_YEAR: return month;
}
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.getFrom(this);
}
......@@ -575,7 +580,7 @@ public final class MonthDay
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.chronology()) {
if (query == TemporalQuery.chronology()) {
return (R) IsoChronology.INSTANCE;
}
return TemporalAccessor.super.query(query);
......@@ -617,6 +622,20 @@ public final class MonthDay
return temporal.with(DAY_OF_MONTH, Math.min(temporal.range(DAY_OF_MONTH).getMaximum(), day));
}
/**
* Formats this month-day using the specified formatter.
* <p>
* This month-day will be passed to the formatter to produce a string.
*
* @param formatter the formatter to use, not null
* @return the formatted month-day string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String format(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Combines this month-day with a year to create a {@code LocalDate}.
......@@ -722,21 +741,6 @@ public final class MonthDay
.toString();
}
/**
* Outputs this month-day as a {@code String} using the formatter.
* <p>
* This month-day will be passed to the formatter
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted month-day string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Writes the object using a
......
......@@ -78,7 +78,6 @@ import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
......@@ -86,6 +85,7 @@ import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.time.zone.ZoneRules;
import java.util.Comparator;
......@@ -436,7 +436,7 @@ public final class OffsetDateTime
* <li>{@code ALIGNED_WEEK_OF_MONTH}
* <li>{@code ALIGNED_WEEK_OF_YEAR}
* <li>{@code MONTH_OF_YEAR}
* <li>{@code EPOCH_MONTH}
* <li>{@code PROLEPTIC_MONTH}
* <li>{@code YEAR_OF_ERA}
* <li>{@code YEAR}
* <li>{@code ERA}
......@@ -469,7 +469,7 @@ public final class OffsetDateTime
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -479,6 +479,7 @@ public final class OffsetDateTime
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override
public ValueRange range(TemporalField field) {
......@@ -502,9 +503,9 @@ public final class OffsetDateTime
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
* {@code EPOCH_DAY}, {@code EPOCH_MONTH} and {@code INSTANT_SECONDS} which are too
* {@code EPOCH_DAY}, {@code PROLEPTIC_MONTH} and {@code INSTANT_SECONDS} which are too
* large to fit in an {@code int} and throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -513,15 +514,20 @@ public final class OffsetDateTime
*
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public int get(TemporalField field) {
if (field instanceof ChronoField) {
switch ((ChronoField) field) {
case INSTANT_SECONDS: throw new DateTimeException("Field too large for an int: " + field);
case OFFSET_SECONDS: return getOffset().getTotalSeconds();
case INSTANT_SECONDS:
throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead");
case OFFSET_SECONDS:
return getOffset().getTotalSeconds();
}
return dateTime.get(field);
}
......@@ -538,7 +544,7 @@ public final class OffsetDateTime
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this date-time.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -548,6 +554,7 @@ public final class OffsetDateTime
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -790,7 +797,7 @@ public final class OffsetDateTime
* <p>
* A simple adjuster might simply set the one of the fields, such as the year field.
* A more complex adjuster might set the date to the last day of the month.
* A selection of common adjustments is provided in {@link java.time.temporal.Adjusters}.
* A selection of common adjustments is provided in {@link TemporalAdjuster}.
* These include finding the "last day of the month" and "next Wednesday".
* Key date-time classes also implement the {@code TemporalAdjuster} interface,
* such as {@link Month} and {@link java.time.MonthDay MonthDay}.
......@@ -867,7 +874,7 @@ public final class OffsetDateTime
* the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}.
* In this case, the offset is not part of the calculation and will be unchanged.
* <p>
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
......@@ -880,6 +887,7 @@ public final class OffsetDateTime
* @param newValue the new value of the field in the result
* @return an {@code OffsetDateTime} based on {@code this} with the specified field set, not null
* @throws DateTimeException if the field cannot be set
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1041,6 +1049,7 @@ public final class OffsetDateTime
* @param unit the unit to truncate to, not null
* @return an {@code OffsetDateTime} based on this date-time with the time truncated, not null
* @throws DateTimeException if unable to truncate
* @throws UnsupportedTemporalTypeException if the unit is not supported
*/
public OffsetDateTime truncatedTo(TemporalUnit unit) {
return with(dateTime.truncatedTo(unit), offset);
......@@ -1094,6 +1103,7 @@ public final class OffsetDateTime
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1285,6 +1295,7 @@ public final class OffsetDateTime
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1453,17 +1464,17 @@ public final class OffsetDateTime
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.offset() || query == Queries.zone()) {
if (query == TemporalQuery.offset() || query == TemporalQuery.zone()) {
return (R) getOffset();
} else if (query == Queries.zoneId()) {
} else if (query == TemporalQuery.zoneId()) {
return null;
} else if (query == Queries.localDate()) {
} else if (query == TemporalQuery.localDate()) {
return (R) toLocalDate();
} else if (query == Queries.localTime()) {
} else if (query == TemporalQuery.localTime()) {
return (R) toLocalTime();
} else if (query == Queries.chronology()) {
} else if (query == TemporalQuery.chronology()) {
return (R) IsoChronology.INSTANCE;
} else if (query == Queries.precision()) {
} else if (query == TemporalQuery.precision()) {
return (R) NANOS;
}
// inline TemporalAccessor.super.query(query) as an optimization
......@@ -1479,8 +1490,8 @@ public final class OffsetDateTime
* with the offset, date and time changed to be the same as this.
* <p>
* The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
* three times, passing {@link ChronoField#OFFSET_SECONDS},
* {@link ChronoField#EPOCH_DAY} and {@link ChronoField#NANO_OF_DAY} as the fields.
* three times, passing {@link ChronoField#EPOCH_DAY},
* {@link ChronoField#NANO_OF_DAY} and {@link ChronoField#OFFSET_SECONDS} as the fields.
* <p>
* In most cases, it is clearer to reverse the calling pattern by using
* {@link Temporal#with(TemporalAdjuster)}:
......@@ -1499,10 +1510,14 @@ public final class OffsetDateTime
*/
@Override
public Temporal adjustInto(Temporal temporal) {
// OffsetDateTime is treated as three separate fields, not an instant
// this produces the most consistent set of results overall
// the offset is set after the date and time, as it is typically a small
// tweak to the result, with ZonedDateTime frequently ignoring the offset
return temporal
.with(OFFSET_SECONDS, getOffset().getTotalSeconds())
.with(EPOCH_DAY, toLocalDate().toEpochDay())
.with(NANO_OF_DAY, toLocalTime().toNanoOfDay());
.with(NANO_OF_DAY, toLocalTime().toNanoOfDay())
.with(OFFSET_SECONDS, getOffset().getTotalSeconds());
}
/**
......@@ -1552,6 +1567,7 @@ public final class OffsetDateTime
* @param unit the unit to measure the period in, not null
* @return the amount of the period between this date-time and the end date-time
* @throws DateTimeException if the period cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1568,6 +1584,20 @@ public final class OffsetDateTime
return unit.between(this, endDateTime);
}
/**
* Formats this date-time using the specified formatter.
* <p>
* This date-time will be passed to the formatter to produce a string.
*
* @param formatter the formatter to use, not null
* @return the formatted date-time string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String format(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Combines this date-time with a time-zone to create a {@code ZonedDateTime}
......@@ -1796,11 +1826,11 @@ public final class OffsetDateTime
* <p>
* The output will be one of the following ISO-8601 formats:
* <p><ul>
* <li>{@code yyyy-MM-dd'T'HH:mmXXXXX}</li>
* <li>{@code yyyy-MM-dd'T'HH:mm:ssXXXXX}</li>
* <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX}</li>
* <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX}</li>
* <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXXXX}</li>
* <li>{@code uuuu-MM-dd'T'HH:mmXXXXX}</li>
* <li>{@code uuuu-MM-dd'T'HH:mm:ssXXXXX}</li>
* <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSXXXXX}</li>
* <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSXXXXX}</li>
* <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSSXXXXX}</li>
* </ul><p>
* The format used will be the shortest that outputs the full value of
* the time where the omitted parts are implied to be zero.
......@@ -1812,21 +1842,6 @@ public final class OffsetDateTime
return dateTime.toString() + offset.toString();
}
/**
* Outputs this date-time as a {@code String} using the formatter.
* <p>
* This date-time will be passed to the formatter
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted date-time string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Writes the object using a
......
......@@ -79,7 +79,6 @@ import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
......@@ -87,6 +86,7 @@ import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.time.zone.ZoneRules;
import java.util.Objects;
......@@ -384,7 +384,7 @@ public final class OffsetTime
@Override
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
return ((ChronoField) field).isTimeField() || field == OFFSET_SECONDS;
return field.isTimeBased() || field == OFFSET_SECONDS;
}
return field != null && field.isSupportedBy(this);
}
......@@ -400,7 +400,7 @@ public final class OffsetTime
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -410,6 +410,7 @@ public final class OffsetTime
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override
public ValueRange range(TemporalField field) {
......@@ -434,7 +435,7 @@ public final class OffsetTime
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY}
* which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -443,7 +444,10 @@ public final class OffsetTime
*
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override // override for Javadoc
......@@ -461,7 +465,7 @@ public final class OffsetTime
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this time.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -471,6 +475,7 @@ public final class OffsetTime
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -655,7 +660,7 @@ public final class OffsetTime
* the matching method on {@link LocalTime#with(TemporalField, long)} LocalTime}.
* In this case, the offset is not part of the calculation and will be unchanged.
* <p>
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
......@@ -668,6 +673,7 @@ public final class OffsetTime
* @param newValue the new value of the field in the result
* @return an {@code OffsetTime} based on {@code this} with the specified field set, not null
* @throws DateTimeException if the field cannot be set
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -764,6 +770,7 @@ public final class OffsetTime
* @param unit the unit to truncate to, not null
* @return an {@code OffsetTime} based on this time with the time truncated, not null
* @throws DateTimeException if unable to truncate
* @throws UnsupportedTemporalTypeException if the unit is not supported
*/
public OffsetTime truncatedTo(TemporalUnit unit) {
return with(time.truncatedTo(unit), offset);
......@@ -817,6 +824,7 @@ public final class OffsetTime
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -930,6 +938,7 @@ public final class OffsetTime
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1020,13 +1029,13 @@ public final class OffsetTime
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.offset() || query == Queries.zone()) {
if (query == TemporalQuery.offset() || query == TemporalQuery.zone()) {
return (R) offset;
} else if (query == Queries.zoneId() | query == Queries.chronology() || query == Queries.localDate()) {
} else if (query == TemporalQuery.zoneId() | query == TemporalQuery.chronology() || query == TemporalQuery.localDate()) {
return null;
} else if (query == Queries.localTime()) {
} else if (query == TemporalQuery.localTime()) {
return (R) time;
} else if (query == Queries.precision()) {
} else if (query == TemporalQuery.precision()) {
return (R) NANOS;
}
// inline TemporalAccessor.super.query(query) as an optimization
......@@ -1042,8 +1051,8 @@ public final class OffsetTime
* with the offset and time changed to be the same as this.
* <p>
* The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
* twice, passing {@link ChronoField#OFFSET_SECONDS} and
* {@link ChronoField#NANO_OF_DAY} as the fields.
* twice, passing {@link ChronoField#NANO_OF_DAY} and
* {@link ChronoField#OFFSET_SECONDS} as the fields.
* <p>
* In most cases, it is clearer to reverse the calling pattern by using
* {@link Temporal#with(TemporalAdjuster)}:
......@@ -1063,8 +1072,8 @@ public final class OffsetTime
@Override
public Temporal adjustInto(Temporal temporal) {
return temporal
.with(OFFSET_SECONDS, offset.getTotalSeconds())
.with(NANO_OF_DAY, time.toNanoOfDay());
.with(NANO_OF_DAY, time.toNanoOfDay())
.with(OFFSET_SECONDS, offset.getTotalSeconds());
}
/**
......@@ -1112,6 +1121,7 @@ public final class OffsetTime
* @param unit the unit to measure the period in, not null
* @return the amount of the period between this time and the end time
* @throws DateTimeException if the period cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -1132,14 +1142,28 @@ public final class OffsetTime
case HOURS: return nanosUntil / NANOS_PER_HOUR;
case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return unit.between(this, endTime);
}
/**
* Formats this time using the specified formatter.
* <p>
* This time will be passed to the formatter to produce a string.
*
* @param formatter the formatter to use, not null
* @return the formatted time string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String format(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Combines this date with a time to create an {@code OffsetDateTime}.
* Combines this time with a date to create an {@code OffsetDateTime}.
* <p>
* This returns an {@code OffsetDateTime} formed from this time and the specified date.
* All possible combinations of date and time are valid.
......@@ -1307,27 +1331,12 @@ public final class OffsetTime
return time.toString() + offset.toString();
}
/**
* Outputs this time as a {@code String} using the formatter.
* <p>
* This time will be passed to the formatter
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted time string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
// -----------------------------------------------------------------------
//-----------------------------------------------------------------------
/**
* Writes the object using a
* <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
* <pre>
* out.writeByte(9); // identifies this as a OffsetDateTime
* out.writeByte(9); // identifies this as a OffsetTime
* out.writeObject(time);
* out.writeObject(offset);
* </pre>
......
......@@ -79,6 +79,7 @@ import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.Arrays;
import java.util.Collections;
......@@ -215,26 +216,40 @@ public final class Period
//-----------------------------------------------------------------------
/**
* Obtains a {@code Period} consisting of the number of years, months,
* and days between two dates.
* <p>
* The start date is included, but the end date is not.
* The period is calculated by removing complete months, then calculating
* the remaining number of days, adjusting to ensure that both have the same sign.
* The number of months is then split into years and months based on a 12 month year.
* A month is considered if the end day-of-month is greater than or equal to the start day-of-month.
* For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days.
* <p>
* The result of this method can be a negative period if the end is before the start.
* The negative sign will be the same in each of year, month and day.
*
* @param startDate the start date, inclusive, not null
* @param endDate the end date, exclusive, not null
* @return the period between this date and the end date, not null
* @see ChronoLocalDate#periodUntil(ChronoLocalDate)
*/
public static Period between(LocalDate startDate, LocalDate endDate) {
return startDate.periodUntil(endDate);
* Obtains an instance of {@code Period} from a temporal amount.
* <p>
* This obtains a period based on the specified amount.
* A {@code TemporalAmount} represents an amount of time, which may be
* date-based or time-based, which this factory extracts to a period.
* <p>
* The conversion loops around the set of units from the amount and uses
* the {@link ChronoUnit#YEARS YEARS}, {@link ChronoUnit#MONTHS MONTHS}
* and {@link ChronoUnit#DAYS DAYS} units to create a period.
* If any other units are found then an exception is thrown.
*
* @param amount the temporal amount to convert, not null
* @return the equivalent period, not null
* @throws DateTimeException if unable to convert to a {@code Period}
* @throws ArithmeticException if the amount of years, months or days exceeds an int
*/
public static Period from(TemporalAmount amount) {
Objects.requireNonNull(amount, "amount");
int years = 0;
int months = 0;
int days = 0;
for (TemporalUnit unit : amount.getUnits()) {
long unitAmount = amount.get(unit);
if (unit == ChronoUnit.YEARS) {
years = Math.toIntExact(unitAmount);
} else if (unit == ChronoUnit.MONTHS) {
months = Math.toIntExact(unitAmount);
} else if (unit == ChronoUnit.DAYS) {
days = Math.toIntExact(unitAmount);
} else {
throw new DateTimeException("Unit must be Years, Months or Days, but was " + unit);
}
}
return create(years, months, days);
}
//-----------------------------------------------------------------------
......@@ -296,6 +311,30 @@ public final class Period
}
}
//-----------------------------------------------------------------------
/**
* Obtains a {@code Period} consisting of the number of years, months,
* and days between two dates.
* <p>
* The start date is included, but the end date is not.
* The period is calculated by removing complete months, then calculating
* the remaining number of days, adjusting to ensure that both have the same sign.
* The number of months is then split into years and months based on a 12 month year.
* A month is considered if the end day-of-month is greater than or equal to the start day-of-month.
* For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days.
* <p>
* The result of this method can be a negative period if the end is before the start.
* The negative sign will be the same in each of year, month and day.
*
* @param startDate the start date, inclusive, not null
* @param endDate the end date, exclusive, not null
* @return the period between this date and the end date, not null
* @see ChronoLocalDate#periodUntil(ChronoLocalDate)
*/
public static Period between(LocalDate startDate, LocalDate endDate) {
return startDate.periodUntil(endDate);
}
//-----------------------------------------------------------------------
/**
* Creates an instance.
......@@ -336,6 +375,7 @@ public final class Period
* @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
* @throws UnsupportedTemporalTypeException if the unit is not supported
*/
@Override
public long get(TemporalUnit unit) {
......@@ -346,7 +386,7 @@ public final class Period
} else if (unit == ChronoUnit.DAYS) {
return getDays();
} else {
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
}
......@@ -499,8 +539,7 @@ public final class Period
/**
* Returns a copy of this period with the specified period added.
* <p>
* This operates separately on the years, months, days and the normalized time.
* There is no further normalization beyond the normalized time.
* This operates separately on the years, months and days.
* <p>
* For example, "1 year, 6 months and 3 days" plus "2 years, 2 months and 2 days"
* returns "3 years, 8 months and 5 days".
......@@ -582,8 +621,7 @@ public final class Period
/**
* Returns a copy of this period with the specified period subtracted.
* <p>
* This operates separately on the years, months, days and the normalized time.
* There is no further normalization beyond the normalized time.
* This operates separately on the years, months and days.
* <p>
* For example, "1 year, 6 months and 3 days" minus "2 years, 2 months and 2 days"
* returns "-1 years, 4 months and 1 day".
......@@ -845,9 +883,11 @@ public final class Period
* @return the month range, negative if not fixed range
*/
private long monthRange(Temporal temporal) {
ValueRange startRange = Chronology.from(temporal).range(MONTH_OF_YEAR);
if (startRange.isFixed() && startRange.isIntValue()) {
return startRange.getMaximum() - startRange.getMinimum() + 1;
if (temporal.isSupported(MONTH_OF_YEAR)) {
ValueRange startRange = Chronology.from(temporal).range(MONTH_OF_YEAR);
if (startRange.isFixed() && startRange.isIntValue()) {
return startRange.getMaximum() - startRange.getMinimum() + 1;
}
}
return -1;
}
......
......@@ -80,7 +80,6 @@ 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;
......@@ -88,6 +87,7 @@ import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.Objects;
......@@ -368,7 +368,7 @@ public final class Year
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -378,6 +378,7 @@ public final class Year
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override
public ValueRange range(TemporalField field) {
......@@ -398,7 +399,7 @@ public final class Year
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this year.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -407,7 +408,10 @@ public final class Year
*
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override // override for Javadoc
......@@ -425,7 +429,7 @@ public final class Year
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this year.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -435,6 +439,7 @@ public final class Year
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -445,7 +450,7 @@ public final class Year
case YEAR: return year;
case ERA: return (year < 1 ? 0 : 1);
}
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.getFrom(this);
}
......@@ -544,7 +549,7 @@ public final class Year
* In all cases, if the new value is outside the valid range of values for the field
* then a {@code DateTimeException} will be thrown.
* <p>
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
......@@ -557,6 +562,7 @@ public final class Year
* @param newValue the new value of the field in the result
* @return a {@code Year} based on {@code this} with the specified field set, not null
* @throws DateTimeException if the field cannot be set
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -569,7 +575,7 @@ public final class Year
case YEAR: return Year.of((int) newValue);
case ERA: return (getLong(ERA) == newValue ? this : Year.of(1 - year));
}
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.adjustInto(this, newValue);
}
......@@ -632,7 +638,7 @@ public final class Year
* is unchanged.
* </ul>
* <p>
* All other {@code ChronoUnit} instances will throw a {@code DateTimeException}.
* All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
......@@ -645,6 +651,7 @@ public final class Year
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -657,7 +664,7 @@ public final class Year
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return unit.addTo(this, amountToAdd);
}
......@@ -705,9 +712,9 @@ public final class Year
}
/**
* Returns a copy of this year-month with the specified amount subtracted.
* Returns a copy of this year with the specified amount subtracted.
* <p>
* This returns a {@code YearMonth}, based on this one, with the amount
* This returns a {@code Year}, 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>
......@@ -718,8 +725,9 @@ public final class Year
*
* @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
* @return a {@code Year} based on this year with the specified amount subtracted, not null
* @throws DateTimeException if the subtraction cannot be made
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -762,9 +770,9 @@ public final class Year
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.chronology()) {
if (query == TemporalQuery.chronology()) {
return (R) IsoChronology.INSTANCE;
} else if (query == Queries.precision()) {
} else if (query == TemporalQuery.precision()) {
return (R) YEARS;
}
return Temporal.super.query(query);
......@@ -846,6 +854,7 @@ public final class Year
* @param unit the unit to measure the period in, not null
* @return the amount of the period between this year and the end year
* @throws DateTimeException if the period cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -864,11 +873,25 @@ public final class Year
case MILLENNIA: return yearsUntil / 1000;
case ERAS: return end.getLong(ERA) - getLong(ERA);
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return unit.between(this, endYear);
}
/**
* Formats this year using the specified formatter.
* <p>
* This year will be passed to the formatter to produce a string.
*
* @param formatter the formatter to use, not null
* @return the formatted year string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String format(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Combines this year with a day-of-year to create a {@code LocalDate}.
......@@ -1014,21 +1037,6 @@ public final class Year
return Integer.toString(year);
}
/**
* Outputs this year as a {@code String} using the formatter.
* <p>
* This year will be passed to the formatter
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted year string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Writes the object using a
......
......@@ -61,9 +61,9 @@
*/
package java.time;
import static java.time.temporal.ChronoField.EPOCH_MONTH;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
import static java.time.temporal.ChronoField.YEAR;
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
import static java.time.temporal.ChronoUnit.MONTHS;
......@@ -82,7 +82,6 @@ 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;
......@@ -90,6 +89,7 @@ import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.Objects;
......@@ -255,7 +255,7 @@ public final class YearMonth
* Obtains an instance of {@code YearMonth} from a text string such as {@code 2007-12}.
* <p>
* The string must represent a valid year-month.
* The format must be {@code yyyy-MM}.
* The format must be {@code uuuu-MM}.
* Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol.
*
* @param text the text to parse such as "2007-12", not null
......@@ -320,7 +320,7 @@ public final class YearMonth
* The supported fields are:
* <ul>
* <li>{@code MONTH_OF_YEAR}
* <li>{@code EPOCH_MONTH}
* <li>{@code PROLEPTIC_MONTH}
* <li>{@code YEAR_OF_ERA}
* <li>{@code YEAR}
* <li>{@code ERA}
......@@ -339,7 +339,7 @@ public final class YearMonth
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
return field == YEAR || field == MONTH_OF_YEAR ||
field == EPOCH_MONTH || field == YEAR_OF_ERA || field == ERA;
field == PROLEPTIC_MONTH || field == YEAR_OF_ERA || field == ERA;
}
return field != null && field.isSupportedBy(this);
}
......@@ -355,7 +355,7 @@ public final class YearMonth
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -365,6 +365,7 @@ public final class YearMonth
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override
public ValueRange range(TemporalField field) {
......@@ -384,9 +385,9 @@ public final class YearMonth
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this year-month, except {@code EPOCH_MONTH} which is too
* values based on this year-month, except {@code PROLEPTIC_MONTH} which is too
* large to fit in an {@code int} and throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -395,7 +396,10 @@ public final class YearMonth
*
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override // override for Javadoc
......@@ -413,7 +417,7 @@ public final class YearMonth
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this year-month.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -423,6 +427,7 @@ public final class YearMonth
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -430,18 +435,18 @@ public final class YearMonth
if (field instanceof ChronoField) {
switch ((ChronoField) field) {
case MONTH_OF_YEAR: return month;
case EPOCH_MONTH: return getEpochMonth();
case PROLEPTIC_MONTH: return getProlepticMonth();
case YEAR_OF_ERA: return (year < 1 ? 1 - year : year);
case YEAR: return year;
case ERA: return (year < 1 ? 0 : 1);
}
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.getFrom(this);
}
private long getEpochMonth() {
return ((year - 1970) * 12L) + (month - 1);
private long getProlepticMonth() {
return (year * 12L + month - 1);
}
//-----------------------------------------------------------------------
......@@ -589,8 +594,8 @@ public final class YearMonth
* <li>{@code MONTH_OF_YEAR} -
* Returns a {@code YearMonth} with the specified month-of-year.
* The year will be unchanged.
* <li>{@code EPOCH_MONTH} -
* Returns a {@code YearMonth} with the specified epoch-month.
* <li>{@code PROLEPTIC_MONTH} -
* Returns a {@code YearMonth} with the specified proleptic-month.
* This completely replaces the year and month of this object.
* <li>{@code YEAR_OF_ERA} -
* Returns a {@code YearMonth} with the specified year-of-era
......@@ -606,7 +611,7 @@ public final class YearMonth
* In all cases, if the new value is outside the valid range of values for the field
* then a {@code DateTimeException} will be thrown.
* <p>
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
......@@ -619,6 +624,7 @@ public final class YearMonth
* @param newValue the new value of the field in the result
* @return a {@code YearMonth} based on {@code this} with the specified field set, not null
* @throws DateTimeException if the field cannot be set
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -628,12 +634,12 @@ public final class YearMonth
f.checkValidValue(newValue);
switch (f) {
case MONTH_OF_YEAR: return withMonth((int) newValue);
case EPOCH_MONTH: return plusMonths(newValue - getLong(EPOCH_MONTH));
case PROLEPTIC_MONTH: return plusMonths(newValue - getProlepticMonth());
case YEAR_OF_ERA: return withYear((int) (year < 1 ? 1 - newValue : newValue));
case YEAR: return withYear((int) newValue);
case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
}
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.adjustInto(this, newValue);
}
......@@ -728,7 +734,7 @@ public final class YearMonth
* is unchanged.
* </ul>
* <p>
* All other {@code ChronoUnit} instances will throw a {@code DateTimeException}.
* All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
......@@ -741,6 +747,7 @@ public final class YearMonth
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -754,7 +761,7 @@ public final class YearMonth
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return unit.addTo(this, amountToAdd);
}
......@@ -838,6 +845,7 @@ public final class YearMonth
* @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 UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -893,9 +901,9 @@ public final class YearMonth
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.chronology()) {
if (query == TemporalQuery.chronology()) {
return (R) IsoChronology.INSTANCE;
} else if (query == Queries.precision()) {
} else if (query == TemporalQuery.precision()) {
return (R) MONTHS;
}
return Temporal.super.query(query);
......@@ -908,7 +916,7 @@ public final class YearMonth
* with the year and month changed to be the same as this.
* <p>
* The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
* passing {@link ChronoField#EPOCH_MONTH} as the field.
* passing {@link ChronoField#PROLEPTIC_MONTH} as the field.
* If the specified temporal object does not use the ISO calendar system then
* a {@code DateTimeException} is thrown.
* <p>
......@@ -932,7 +940,7 @@ public final class YearMonth
if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
throw new DateTimeException("Adjustment only supported on ISO date-time");
}
return temporal.with(EPOCH_MONTH, getEpochMonth());
return temporal.with(PROLEPTIC_MONTH, getProlepticMonth());
}
/**
......@@ -977,6 +985,7 @@ public final class YearMonth
* @param unit the unit to measure the period in, not null
* @return the amount of the period between this year-month and the end year-month
* @throws DateTimeException if the period cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -987,7 +996,7 @@ public final class YearMonth
}
YearMonth end = (YearMonth) endYearMonth;
if (unit instanceof ChronoUnit) {
long monthsUntil = end.getEpochMonth() - getEpochMonth(); // no overflow
long monthsUntil = end.getProlepticMonth() - getProlepticMonth(); // no overflow
switch ((ChronoUnit) unit) {
case MONTHS: return monthsUntil;
case YEARS: return monthsUntil / 12;
......@@ -996,11 +1005,25 @@ public final class YearMonth
case MILLENNIA: return monthsUntil / 12000;
case ERAS: return end.getLong(ERA) - getLong(ERA);
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return unit.between(this, endYearMonth);
}
/**
* Formats this year-month using the specified formatter.
* <p>
* This year-month will be passed to the formatter to produce a string.
*
* @param formatter the formatter to use, not null
* @return the formatted year-month string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String format(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Combines this year-month with a day-of-month to create a {@code LocalDate}.
......@@ -1115,7 +1138,7 @@ public final class YearMonth
/**
* Outputs this year-month as a {@code String}, such as {@code 2007-12}.
* <p>
* The output will be in the format {@code yyyy-MM}:
* The output will be in the format {@code uuuu-MM}:
*
* @return a string representation of this year-month, not null
*/
......@@ -1137,21 +1160,6 @@ public final class YearMonth
.toString();
}
/**
* Outputs this year-month as a {@code String} using the formatter.
* <p>
* This year-month will be passed to the formatter
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted year-month string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Writes the object using a
......
......@@ -61,6 +61,7 @@
*/
package java.time;
import java.time.temporal.UnsupportedTemporalTypeException;
import static java.time.LocalTime.MINUTES_PER_HOUR;
import static java.time.LocalTime.SECONDS_PER_HOUR;
import static java.time.LocalTime.SECONDS_PER_MINUTE;
......@@ -73,7 +74,6 @@ import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.temporal.ChronoField;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
......@@ -322,7 +322,7 @@ public final class ZoneOffset
* 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 uses the {@link Queries#offset()} query, which relies
* The conversion uses the {@link TemporalQuery#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}
......@@ -333,7 +333,7 @@ public final class ZoneOffset
* @throws DateTimeException if unable to convert to an {@code ZoneOffset}
*/
public static ZoneOffset from(TemporalAccessor temporal) {
ZoneOffset offset = temporal.query(Queries.offset());
ZoneOffset offset = temporal.query(TemporalQuery.offset());
if (offset == null) {
throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " + temporal.getClass());
}
......@@ -534,7 +534,7 @@ public final class ZoneOffset
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
......@@ -544,6 +544,7 @@ public final class ZoneOffset
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
* @throws DateTimeException if the range for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
*/
@Override // override for Javadoc
public ValueRange range(TemporalField field) {
......@@ -560,7 +561,7 @@ public final class ZoneOffset
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@code OFFSET_SECONDS} field returns the value of the offset.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -569,7 +570,10 @@ public final class ZoneOffset
*
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if a value for the field cannot be obtained or
* the value is outside the range of valid values for the field
* @throws UnsupportedTemporalTypeException if the field is not supported or
* the range of values exceeds an {@code int}
* @throws ArithmeticException if numeric overflow occurs
*/
@Override // override for Javadoc and performance
......@@ -577,7 +581,7 @@ public final class ZoneOffset
if (field == OFFSET_SECONDS) {
return totalSeconds;
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return range(field).checkValidIntValue(getLong(field), field);
}
......@@ -591,7 +595,7 @@ public final class ZoneOffset
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@code OFFSET_SECONDS} field returns the value of the offset.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
......@@ -601,6 +605,7 @@ public final class ZoneOffset
* @param field the field to get, not null
* @return the value for the field
* @throws DateTimeException if a value for the field cannot be obtained
* @throws UnsupportedTemporalTypeException if the field is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -608,7 +613,7 @@ public final class ZoneOffset
if (field == OFFSET_SECONDS) {
return totalSeconds;
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.getFrom(this);
}
......@@ -635,7 +640,7 @@ public final class ZoneOffset
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.offset() || query == Queries.zone()) {
if (query == TemporalQuery.offset() || query == TemporalQuery.zone()) {
return (R) this;
}
return TemporalAccessor.super.query(query);
......
......@@ -94,11 +94,6 @@ final class ZoneRegion extends ZoneId implements Serializable {
* Serialization version.
*/
private static final long serialVersionUID = 8386373296231747096L;
/**
* The regex pattern for region IDs.
*/
private static final Pattern PATTERN = Pattern.compile("[A-Za-z][A-Za-z0-9~/._+-]+");
/**
* The time-zone ID, not null.
*/
......@@ -108,26 +103,6 @@ final class ZoneRegion extends ZoneId implements Serializable {
*/
private final transient ZoneRules rules;
/**
* Obtains an instance of {@code ZoneRegion} from an identifier without checking
* if the time-zone has available rules.
* <p>
* This method parses the ID and applies any appropriate normalization.
* It does not validate the ID against the known set of 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.
* Using this factory would allow a {@code ZoneRegion}, and thus a {@code ZonedDateTime},
* to be created without loading the rules from the remote server.
*
* @param zoneId the time-zone ID, not null
* @return the zone ID, not null
* @throws DateTimeException if the ID format is invalid
*/
private static ZoneRegion ofLenient(String zoneId) {
return ofId(zoneId, false);
}
/**
* Obtains an instance of {@code ZoneId} from an identifier.
*
......@@ -139,12 +114,7 @@ final class ZoneRegion extends ZoneId implements Serializable {
*/
static ZoneRegion ofId(String zoneId, boolean checkAvailable) {
Objects.requireNonNull(zoneId, "zoneId");
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);
}
checkName(zoneId);
ZoneRules rules = null;
try {
// always attempt load for better behavior after deserialization
......@@ -157,6 +127,45 @@ final class ZoneRegion extends ZoneId implements Serializable {
return new ZoneRegion(zoneId, rules);
}
/**
* Checks that the given string is a legal ZondId name.
*
* @param zoneId the time-zone ID, not null
* @throws DateTimeException if the ID format is invalid
*/
private static void checkName(String zoneId) {
int n = zoneId.length();
if (n < 2) {
throw new DateTimeException("Invalid ID for region-based ZoneId, invalid format: " + zoneId);
}
for (int i = 0; i < n; i++) {
char c = zoneId.charAt(i);
if (c >= 'a' && c <= 'z') continue;
if (c >= 'A' && c <= 'Z') continue;
if (c == '/' && i != 0) continue;
if (c >= '0' && c <= '9' && i != 0) continue;
if (c == '~' && i != 0) continue;
if (c == '.' && i != 0) continue;
if (c == '_' && i != 0) continue;
if (c == '+' && i != 0) continue;
if (c == '-' && i != 0) continue;
throw new DateTimeException("Invalid ID for region-based ZoneId, invalid format: " + zoneId);
}
}
/**
* Obtains an instance of {@code ZoneId} wrapping an offset.
* <p>
* For example, zone IDs like 'UTC', 'GMT', 'UT' and 'UTC+01:30' will be setup here.
*
* @param zoneId the time-zone ID, not null
* @param offset the offset, not null
* @return the zone ID, not null
*/
static ZoneRegion ofPrefixedOffset(String zoneId, ZoneOffset offset) {
return new ZoneRegion(zoneId, offset.getRules());
}
//-------------------------------------------------------------------------
/**
* Constructor.
......@@ -218,7 +227,7 @@ final class ZoneRegion extends ZoneId implements Serializable {
static ZoneId readExternal(DataInput in) throws IOException {
String id = in.readUTF();
return ofLenient(id);
return ZoneId.of(id, false);
}
}
......@@ -59,19 +59,18 @@ package java.time.chrono;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
import java.io.Serializable;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.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;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.Objects;
/**
* A date expressed in terms of a standard year-month-day calendar system.
......@@ -97,12 +96,12 @@ import java.time.temporal.TemporalUnit;
* // Enumerate the list of available calendars and print today for each
* Set&lt;Chronology&gt; chronos = Chronology.getAvailableChronologies();
* for (Chronology chrono : chronos) {
* ChronoLocalDate<?> date = chrono.dateNow();
* ChronoLocalDate&lt;?&gt; date = chrono.dateNow();
* System.out.printf(" %20s: %s%n", chrono.getID(), date.toString());
* }
*
* // Print the Hijrah date and calendar
* ChronoLocalDate<?> date = Chronology.of("Hijrah").dateNow();
* ChronoLocalDate&lt;?&gt; 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);
......@@ -111,10 +110,10 @@ import java.time.temporal.TemporalUnit;
* dow, day, month, year);
* // Print today's date and the last day of the year
* ChronoLocalDate<?> now1 = Chronology.of("Hijrah").dateNow();
* ChronoLocalDate<?> first = now1.with(ChronoField.DAY_OF_MONTH, 1)
* ChronoLocalDate&lt;?&gt; now1 = Chronology.of("Hijrah").dateNow();
* ChronoLocalDate&lt;?&gt; first = now1.with(ChronoField.DAY_OF_MONTH, 1)
* .with(ChronoField.MONTH_OF_YEAR, 1);
* ChronoLocalDate<?> last = first.plus(1, ChronoUnit.YEARS)
* ChronoLocalDate&lt;?&gt; last = first.plus(1, ChronoUnit.YEARS)
* .minus(1, ChronoUnit.DAYS);
* System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChronology().getID(),
* first, last);
......@@ -168,7 +167,7 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return ChronoLocalDate.super.plus(amountToAdd, unit);
}
......@@ -323,6 +322,8 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
*/
@Override
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
Objects.requireNonNull(endDateTime, "endDateTime");
Objects.requireNonNull(unit, "unit");
if (endDateTime instanceof ChronoLocalDate == false) {
throw new DateTimeException("Unable to calculate period between objects of two different types");
}
......@@ -331,11 +332,35 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
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
switch ((ChronoUnit) unit) {
case DAYS: return daysUntil(end);
case WEEKS: return daysUntil(end) / 7;
case MONTHS: return monthsUntil(end);
case YEARS: return monthsUntil(end) / 12;
case DECADES: return monthsUntil(end) / 120;
case CENTURIES: return monthsUntil(end) / 1200;
case MILLENNIA: return monthsUntil(end) / 12000;
case ERAS: return end.getLong(ERA) - getLong(ERA);
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
}
return unit.between(this, endDateTime);
}
private long daysUntil(ChronoLocalDate<?> end) {
return end.toEpochDay() - toEpochDay(); // no overflow
}
private long monthsUntil(ChronoLocalDate<?> end) {
ValueRange range = getChronology().range(MONTH_OF_YEAR);
if (range.getMaximum() != 12) {
throw new IllegalStateException("ChronoDateImpl only supports Chronologies with 12 months per year");
}
long packed1 = getLong(PROLEPTIC_MONTH) * 32L + get(DAY_OF_MONTH); // no overflow
long packed2 = end.getLong(PROLEPTIC_MONTH) * 32L + end.get(DAY_OF_MONTH); // no overflow
return (packed2 - packed1) / 32;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
......
......@@ -167,6 +167,7 @@ final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
* @param zone the zone identifier, not null
* @return the zoned date-time, not null
*/
@SuppressWarnings("rawtypes")
static ChronoZonedDateTimeImpl<?> ofInstant(Chronology chrono, Instant instant, ZoneId zone) {
ZoneRules rules = zone.getRules();
ZoneOffset offset = rules.getOffset(instant);
......
此差异已折叠。
此差异已折叠。
......@@ -178,7 +178,7 @@ public enum ChronoUnit implements TemporalUnit {
* Unit that represents the concept of an era.
* The ISO calendar system doesn't have eras thus it is impossible to add
* an era to a date or date-time.
* The estimated duration of the era is artificially defined as {@code 1,000,00,000 Years}.
* The estimated duration of the era is artificially defined as {@code 1,000,000,000 Years}.
* <p>
* When used with other calendar systems there are no restrictions on the unit.
*/
......
......@@ -321,7 +321,7 @@ public final class ZoneOffsetTransition
}
/**
* Does this transition represent a gap in the local time-line.
* Does this transition represent an overlap in the local time-line.
* <p>
* Overlaps occur where there are local date-times that exist twice.
* An example would be when the offset changes from {@code +02:00} to {@code +01:00}.
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册