提交 f2141189 编写于 作者: S sherman

8007392: JSR 310: DateTime API Updates

8007520: Update date/time classes in j.util and j.sql packages
8007572: Replace existing jdk timezone data at <java.home>/lib/zi with JSR310's tzdb
Summary: Integration of JSR310 Date/Time API for M7
Reviewed-by: darcy, alanb, naoto
Contributed-by: scolebourne@joda.org, roger.riggs@oracle.com, masayoshi.okutsu@oracle.com, patrick.zhang@oracle.com
上级 09d88d90
......@@ -128,9 +128,9 @@ CORE_PKGS = \
java.text \
java.text.spi \
java.time \
java.time.temporal \
java.time.calendar \
java.time.chrono \
java.time.format \
java.time.temporal \
java.time.zone \
java.util \
java.util.concurrent \
......
......@@ -255,7 +255,6 @@ JAVA_JAVA_java = \
java/util/SimpleTimeZone.java \
sun/util/calendar/ZoneInfo.java \
sun/util/calendar/ZoneInfoFile.java \
sun/util/calendar/TzIDOldMapping.java \
java/util/TooManyListenersException.java \
java/util/Comparator.java \
java/util/Collections.java \
......
......@@ -70,7 +70,7 @@ else
endif
# nio need to be compiled before awt to have all charsets ready
SUBDIRS = jar security javazic misc net nio text util launcher cldr tzdb
SUBDIRS = jar security misc net nio text util launcher cldr tzdb
ifdef BUILD_HEADLESS_ONLY
DISPLAY_LIBS = awt $(HEADLESS_SUBDIR)
......
......@@ -33,11 +33,11 @@ include $(BUILDDIR)/common/Defs.gmk
# Time zone data file creation
TZDATA = ./tzdata/
TZDATA_VER = `$(GREP) '^tzdata' $(TZDATA)VERSION`
TZDATA_VER := $(shell $(GREP) '^tzdata' $(TZDATA)VERSION)
TZFILE = \
africa antarctica asia australasia europe northamerica \
pacificnew southamerica backward \
etcetera solar87 solar88 solar89 systemv
etcetera systemv
JDKTZDATA = ./tzdata_jdk/
JDKTZFILES = gmt jdk11_backward
TZFILES = \
......
#
# Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone GMT 0:00 - GMT
#
# Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# JDK 1.1.x compatible time zone IDs
#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule SystemV min 1973 - Apr lastSun 2:00 1:00 D
Rule SystemV min 1973 - Oct lastSun 2:00 0 S
Rule SystemV 1974 only - Jan 6 2:00 1:00 D
Rule SystemV 1974 only - Nov lastSun 2:00 0 S
Rule SystemV 1975 only - Feb 23 2:00 1:00 D
Rule SystemV 1975 only - Oct lastSun 2:00 0 S
Rule SystemV 1976 max - Apr lastSun 2:00 1:00 D
Rule SystemV 1976 max - Oct lastSun 2:00 0 S
# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL]
Zone SystemV/AST4ADT -4:00 SystemV A%sT
Zone SystemV/EST5EDT -5:00 SystemV E%sT
Zone SystemV/CST6CDT -6:00 SystemV C%sT
Zone SystemV/MST7MDT -7:00 SystemV M%sT
Zone SystemV/PST8PDT -8:00 SystemV P%sT
Zone SystemV/YST9YDT -9:00 SystemV Y%sT
Zone SystemV/AST4 -4:00 - AST
Zone SystemV/EST5 -5:00 - EST
Zone SystemV/CST6 -6:00 - CST
Zone SystemV/MST7 -7:00 - MST
Zone SystemV/PST8 -8:00 - PST
Zone SystemV/YST9 -9:00 - YST
Zone SystemV/HST10 -10:00 - HST
......@@ -43,9 +43,15 @@ BUILD_MANIFEST=true
#
TZDATA_DIR := ../javazic/tzdata
TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION))
TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera
TZFILE := \
africa antarctica asia australasia europe northamerica \
pacificnew southamerica backward etcetera \
gmt jdk11_backward
TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZFILE))
TZDB_JAR = tzdb.jar
#
......@@ -61,7 +67,7 @@ build: $(LIBDIR)/$(TZDB_JAR)
$(LIBDIR)/$(TZDB_JAR): $(TZFILES)
$(prep-target)
echo build tzdb from version $(TZDATA_VER)
$(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar -verbose \
$(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar \
-version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(LIBDIR) $(TZFILE)
clean clobber::
......
......@@ -48,7 +48,6 @@ SUBDIRS = \
hasher_classes \
jarreorder \
jarsplit \
javazic \
jdwpgen \
makeclasslist \
strip_properties \
......
......@@ -490,11 +490,16 @@ class Zoneinfo {
tz.addUsedRec(rrec);
usedZone = true;
}
} else {
} else { // fromTime == minTime
int save = rrec.getSave();
tz.addTransition(fromTime,
tz.addTransition(minTime,
tz.getOffsetIndex(gmtOffset),
tz.getDstOffsetIndex(0));
tz.addTransition(transition,
tz.getOffsetIndex(gmtOffset+save),
tz.getDstOffsetIndex(save));
tz.addUsedRec(rrec);
usedZone = true;
}
......
......@@ -227,6 +227,7 @@ public final class TzdbZoneRulesCompiler {
Map<String, SortedMap<String, ZoneRules>> allBuiltZones = new TreeMap<>();
Set<String> allRegionIds = new TreeSet<String>();
Set<ZoneRules> allRules = new HashSet<ZoneRules>();
Map<String, Map<String, String>> allLinks = new TreeMap<>();
for (File srcDir : srcDirs) {
// source files in this directory
......@@ -242,7 +243,8 @@ public final class TzdbZoneRulesCompiler {
}
// compile
String loopVersion = srcDir.getName();
String loopVersion = (srcDirs.size() == 1 && version != null)
? version : srcDir.getName();
TzdbZoneRulesCompiler compiler = new TzdbZoneRulesCompiler(loopVersion, srcFiles, verbose);
try {
// compile
......@@ -255,12 +257,13 @@ public final class TzdbZoneRulesCompiler {
if (verbose) {
System.out.println("Outputting file: " + dstFile);
}
outputFile(dstFile, loopVersion, builtZones);
outputFile(dstFile, loopVersion, builtZones, compiler.links);
// create totals
allBuiltZones.put(loopVersion, builtZones);
allRegionIds.addAll(builtZones.keySet());
allRules.addAll(builtZones.values());
allLinks.put(loopVersion, compiler.links);
} catch (Exception ex) {
System.out.println("Failed: " + ex.toString());
ex.printStackTrace();
......@@ -274,7 +277,7 @@ public final class TzdbZoneRulesCompiler {
if (verbose) {
System.out.println("Outputting combined file: " + dstFile);
}
outputFile(dstFile, allBuiltZones, allRegionIds, allRules);
outputFile(dstFile, allBuiltZones, allRegionIds, allRules, allLinks);
}
}
......@@ -283,12 +286,15 @@ public final class TzdbZoneRulesCompiler {
*/
private static void outputFile(File dstFile,
String version,
SortedMap<String, ZoneRules> builtZones) {
SortedMap<String, ZoneRules> builtZones,
Map<String, String> links) {
Map<String, SortedMap<String, ZoneRules>> loopAllBuiltZones = new TreeMap<>();
loopAllBuiltZones.put(version, builtZones);
Set<String> loopAllRegionIds = new TreeSet<String>(builtZones.keySet());
Set<ZoneRules> loopAllRules = new HashSet<ZoneRules>(builtZones.values());
outputFile(dstFile, loopAllBuiltZones, loopAllRegionIds, loopAllRules);
Map<String, Map<String, String>> loopAllLinks = new TreeMap<>();
loopAllLinks.put(version, links);
outputFile(dstFile, loopAllBuiltZones, loopAllRegionIds, loopAllRules, loopAllLinks);
}
/**
......@@ -297,10 +303,10 @@ public final class TzdbZoneRulesCompiler {
private static void outputFile(File dstFile,
Map<String, SortedMap<String, ZoneRules>> allBuiltZones,
Set<String> allRegionIds,
Set<ZoneRules> allRules)
{
Set<ZoneRules> allRules,
Map<String, Map<String, String>> allLinks) {
try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(dstFile))) {
outputTZEntry(jos, allBuiltZones, allRegionIds, allRules);
outputTZEntry(jos, allBuiltZones, allRegionIds, allRules, allLinks);
} catch (Exception ex) {
System.out.println("Failed: " + ex.toString());
ex.printStackTrace();
......@@ -314,7 +320,8 @@ public final class TzdbZoneRulesCompiler {
private static void outputTZEntry(JarOutputStream jos,
Map<String, SortedMap<String, ZoneRules>> allBuiltZones,
Set<String> allRegionIds,
Set<ZoneRules> allRules) {
Set<ZoneRules> allRules,
Map<String, Map<String, String>> allLinks) {
// this format is not publicly specified
try {
jos.putNextEntry(new ZipEntry("TZDB.dat"));
......@@ -359,6 +366,16 @@ public final class TzdbZoneRulesCompiler {
out.writeShort(rulesIndex);
}
}
// alias-region
for (String version : allLinks.keySet()) {
out.writeShort(allLinks.get(version).size());
for (Map.Entry<String, String> entry : allLinks.get(version).entrySet()) {
int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey());
int regionIndex = Arrays.binarySearch(regionArray, entry.getValue());
out.writeShort(aliasIndex);
out.writeShort(regionIndex);
}
}
out.flush();
jos.closeEntry();
} catch (Exception ex) {
......@@ -621,7 +638,8 @@ public final class TzdbZoneRulesCompiler {
private int parseYear(String str, int defaultYear) {
if (YEAR.reset(str).matches()) {
if (YEAR.group("min") != null) {
return YEAR_MIN_VALUE;
//return YEAR_MIN_VALUE;
return 1900; // systemv has min
} else if (YEAR.group("max") != null) {
return YEAR_MAX_VALUE;
} else if (YEAR.group("only") != null) {
......@@ -742,16 +760,20 @@ public final class TzdbZoneRulesCompiler {
if (realRules == null) {
throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId + "' for '" + version + "'");
}
links.put(aliasId, realId);
}
builtZones.put(aliasId, realRules);
}
// remove UTC and GMT
builtZones.remove("UTC");
builtZones.remove("GMT");
builtZones.remove("GMT0");
//builtZones.remove("UTC");
//builtZones.remove("GMT");
//builtZones.remove("GMT0");
builtZones.remove("GMT+0");
builtZones.remove("GMT-0");
links.remove("GMT+0");
links.remove("GMT-0");
}
//-----------------------------------------------------------------------
......@@ -785,7 +807,6 @@ public final class TzdbZoneRulesCompiler {
boolean endOfDay;
/** The time of the cutover. */
TimeDefinition timeDefinition = TimeDefinition.WALL;
void adjustToFowards(int year) {
if (adjustForwards == false && dayOfMonth > 0) {
LocalDate adjustedDate = LocalDate.of(year, month, dayOfMonth).minusDays(6);
......
......@@ -30,7 +30,7 @@ GENDATA_TZDB :=
#
TZDATA_DIR := $(JDK_TOPDIR)/make/sun/javazic/tzdata
TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION))
TZDATA_TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera
TZDATA_TZFILE := africa antarctica asia australasia europe northamerica pacificnew southamerica backward etcetera gmt jdk11_backward
TZDATA_TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZDATA_TZFILE))
GENDATA_TZDB_DST := $(JDK_OUTPUTDIR)/lib
......@@ -39,6 +39,6 @@ GENDATA_TZDB_JAR := tzdb.jar
$(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR) : $(TZDATA_TZFILES)
$(RM) $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)
echo building tzdb from version $(TZDATA_VER)
$(TOOL_TZDB) -verbose -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(GENDATA_TZDB_DST) $(TZDATA_TZFILE)
$(TOOL_TZDB) -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(GENDATA_TZDB_DST) $(TZDATA_TZFILE)
GENDATA_TZDB += $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)
......@@ -34,7 +34,7 @@ GENDATA_TIMEZONE_TMP := $(JDK_OUTPUTDIR)/gendata_timezone
TZFILE0 := \
africa antarctica asia australasia europe northamerica \
pacificnew southamerica backward \
etcetera solar87 solar88 solar89 systemv
etcetera systemv
TZFILE1 := \
gmt jdk11_backward
......
......@@ -44,9 +44,6 @@ GENDATA += $(BREAK_ITERATOR)
include GendataFontConfig.gmk
GENDATA += $(GENDATA_FONT_CONFIG)
include GendataTimeZone.gmk
GENDATA += $(GENDATA_TIMEZONE)
include GendataTZDB.gmk
GENDATA += $(GENDATA_TZDB)
......
......@@ -103,9 +103,6 @@ TOOL_HASHER=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \
TOOL_JARSPLIT=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \
build.tools.jarsplit.JarSplit
TOOL_JAVAZIC=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \
build.tools.javazic.Main
TOOL_TZDB=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \
build.tools.tzdb.TzdbZoneRulesCompiler
......
......@@ -25,6 +25,9 @@
package java.sql;
import java.time.Instant;
import java.time.LocalDate;
/**
* <P>A thin wrapper around a millisecond value that allows
* JDBC to identify this as an SQL <code>DATE</code> value. A
......@@ -113,7 +116,6 @@ public class Date extends java.util.Date {
int firstDash;
int secondDash;
Date d = null;
if (s == null) {
throw new java.lang.IllegalArgumentException();
}
......@@ -255,4 +257,50 @@ public class Date extends java.util.Date {
* compatibility.
*/
static final long serialVersionUID = 1511598038487230103L;
/**
* Obtains an instance of {@code Date} from a {@link LocalDate} object
* with the same year, month and day of month value as the given
* {@code LocalDate}.
* <p>
* The provided {@code LocalDate} is interpreted as the local date
* in the local time zone.
*
* @param date a {@code LocalDate} to convert
* @return a {@code Date} object
* @exception NullPointerException if {@code date} is null
* @since 1.8
*/
@SuppressWarnings("deprecation")
public static Date valueOf(LocalDate date) {
return new Date(date.getYear() - 1900, date.getMonthValue() -1,
date.getDayOfMonth());
}
/**
* Converts this {@code Date} object to a {@code LocalDate}
* <p>
* The conversion creates a {@code LocalDate} that represents the same
* date value as this {@code Date} in local time zone
*
* @return a {@code LocalDate} object representing the same date value
*
* @since 1.8
*/
@SuppressWarnings("deprecation")
public LocalDate toLocalDate() {
return LocalDate.of(getYear() + 1900, getMonth() + 1, getDate());
}
/**
* This method always throws an UnsupportedOperationException and should
* not be used because SQL {@code Date} values do not have a time
* component.
*
* @exception java.lang.UnsupportedOperationException if this method is invoked
*/
@Override
public Instant toInstant() {
throw new java.lang.UnsupportedOperationException();
}
}
......@@ -25,6 +25,9 @@
package java.sql;
import java.time.Instant;
import java.time.LocalTime;
/**
* <P>A thin wrapper around the <code>java.util.Date</code> class that allows the JDBC
* API to identify this as an SQL <code>TIME</code> value. The <code>Time</code>
......@@ -246,4 +249,45 @@ public class Time extends java.util.Date {
* compatibility.
*/
static final long serialVersionUID = 8397324403548013681L;
/**
* Obtains an instance of {@code Time} from a {@link LocalTime} object
* with the same hour, minute and second time value as the given
* {@code LocalTime}.
*
* @param time a {@code LocalTime} to convert
* @return a {@code Time} object
* @exception NullPointerException if {@code time} is null
* @since 1.8
*/
@SuppressWarnings("deprecation")
public static Time valueOf(LocalTime time) {
return new Time(time.getHour(), time.getMinute(), time.getSecond());
}
/**
* Converts this {@code Time} object to a {@code LocalTime}.
* <p>
* The conversion creates a {@code LocalTime} that represents the same
* hour, minute, and second time value as this {@code Time}.
*
* @return a {@code LocalTime} object representing the same time value
* @since 1.8
*/
@SuppressWarnings("deprecation")
public LocalTime toLocalTime() {
return LocalTime.of(getHours(), getMinutes(), getSeconds());
}
/**
* This method always throws an UnsupportedOperationException and should
* not be used because SQL {@code Time} values do not have a date
* component.
*
* @exception java.lang.UnsupportedOperationException if this method is invoked
*/
@Override
public Instant toInstant() {
throw new java.lang.UnsupportedOperationException();
}
}
......@@ -25,6 +25,8 @@
package java.sql;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.StringTokenizer;
/**
......@@ -485,7 +487,6 @@ public class Timestamp extends java.util.Date {
}
}
return i;
}
/**
......@@ -530,4 +531,89 @@ public class Timestamp extends java.util.Date {
static final long serialVersionUID = 2745179027874758501L;
private static final int MILLIS_PER_SECOND = 1000;
/**
* Obtains an instance of {@code Timestamp} from a {@code LocalDateTime}
* object, with the same year, month, day of month, hours, minutes,
* seconds and nanos date-time value as the provided {@code LocalDateTime}.
* <p>
* The provided {@code LocalDateTime} is interpreted as the local
* date-time in the local time zone.
*
* @param dateTime a {@code LocalDateTime} to convert
* @return a {@code Timestamp} object
* @exception NullPointerException if {@code dateTime} is null.
* @since 1.8
*/
@SuppressWarnings("deprecation")
public static Timestamp valueOf(LocalDateTime dateTime) {
return new Timestamp(dateTime.getYear() - 1900,
dateTime.getMonthValue() - 1,
dateTime.getDayOfMonth(),
dateTime.getHour(),
dateTime.getMinute(),
dateTime.getSecond(),
dateTime.getNano());
}
/**
* Converts this {@code Timestamp} object to a {@code LocalDateTime}.
* <p>
* The conversion creates a {@code LocalDateTime} that represents the
* same year, month, day of month, hours, minutes, seconds and nanos
* date-time value as this {@code Timestamp} in the local time zone.
*
* @return a {@code LocalDateTime} object representing the same date-time value
* @since 1.8
*/
@SuppressWarnings("deprecation")
public LocalDateTime toLocalDateTime() {
return LocalDateTime.of(getYear() + 1900,
getMonth() + 1,
getDate(),
getHours(),
getMinutes(),
getSeconds(),
getNanos());
}
/**
* Obtains an instance of {@code Timestamp} from an {@link Instant} object.
* <p>
* {@code Instant} can store points on the time-line further in the future
* and further in the past than {@code Date}. In this scenario, this method
* will throw an exception.
*
* @param instant the instant to convert
* @return an {@code Timestamp} representing the same point on the time-line as
* the provided instant
* @exception NullPointerException if {@code instant} is null.
* @exception IllegalArgumentException if the instant is too large to
* represent as a {@code Timesamp}
* @since 1.8
*/
public static Timestamp from(Instant instant) {
try {
Timestamp stamp = new Timestamp(instant.getEpochSecond() * MILLIS_PER_SECOND);
stamp.nanos = instant.getNano();
return stamp;
} catch (ArithmeticException ex) {
throw new IllegalArgumentException(ex);
}
}
/**
* Converts this {@code Timestamp} object to an {@code Instant}.
* <p>
* The conversion creates an {@code Instant} that represents the same
* point on the time-line as this {@code Timestamp}.
*
* @return an instant representing the same point on the time-line
* @since 1.8
*/
@Override
public Instant toInstant() {
return Instant.ofEpochSecond(super.getTime() / MILLIS_PER_SECOND, nanos);
}
}
......@@ -377,60 +377,57 @@ public abstract class Clock {
* an instant on the time-line rather than a raw millisecond value.
* This method is provided to allow the use of the clock in high performance use cases
* where the creation of an object would be unacceptable.
* <p>
* The default implementation currently calls {@link #instant}.
*
* @return the current millisecond instant from this clock, measured from
* the Java epoch of 1970-01-01T00:00 UTC, not null
* @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
*/
public abstract long millis();
public long millis() {
return instant().toEpochMilli();
}
//-----------------------------------------------------------------------
/**
* Gets the current instant of the clock.
* <p>
* This returns an instant representing the current instant as defined by the clock.
* <p>
* The default implementation currently calls {@link #millis}.
*
* @return the current instant from this clock, not null
* @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
*/
public Instant instant() {
return Instant.ofEpochMilli(millis());
}
public abstract Instant instant();
//-----------------------------------------------------------------------
/**
* Checks if this clock is equal to another clock.
* <p>
* Clocks must compare equal based on their state and behavior.
* Clocks should override this method to compare equals based on
* their state and to meet the contract of {@link Object#equals}.
* If not overridden, the behavior is defined by {@link Object#equals}
*
* @param obj the object to check, null returns false
* @return true if this is equal to the other clock
*/
@Override
public abstract boolean equals(Object obj);
public boolean equals(Object obj) {
return super.equals(obj);
}
/**
* A hash code for this clock.
*
* @return a suitable hash code
*/
@Override
public abstract int hashCode();
//-----------------------------------------------------------------------
/**
* Returns a string describing this clock.
* <p>
* Clocks must have a string representation based on their state and behavior.
* For example, 'System[Europe/Paris]' could be used to represent the System
* clock in the 'Europe/Paris' time-zone.
* Clocks should override this method based on
* their state and to meet the contract of {@link Object#hashCode}.
* If not overridden, the behavior is defined by {@link Object#hashCode}
*
* @return a string representation of this clock, not null
* @return a suitable hash code
*/
@Override
public abstract String toString();
public int hashCode() {
return super.hashCode();
}
//-----------------------------------------------------------------------
/**
......@@ -460,6 +457,10 @@ public abstract class Clock {
return System.currentTimeMillis();
}
@Override
public Instant instant() {
return Instant.ofEpochMilli(millis());
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SystemClock) {
return zone.equals(((SystemClock) obj).zone);
......
......@@ -170,8 +170,9 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
/**
* Obtains an instance of {@code DayOfWeek} from a temporal object.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code DayOfWeek}.
* This obtains a day-of-week based on the specified temporal.
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
* which this factory converts to an instance of {@code DayOfWeek}.
* <p>
* The conversion extracts the {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} field.
* <p>
......@@ -206,8 +207,9 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
/**
* Gets the textual representation, such as 'Mon' or 'Friday'.
* <p>
* This returns the textual name used to identify the day-of-week.
* The parameters control the length of the returned text and the locale.
* This returns the textual name used to identify the day-of-week,
* suitable for presentation to the user.
* The parameters control the style of the returned text and the locale.
* <p>
* If no textual mapping is found then the {@link #getValue() numeric value} is returned.
*
......@@ -215,8 +217,8 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* @param locale the locale to use, not null
* @return the text value of the day-of-week, not null
*/
public String getText(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).print(this);
public String getDisplayName(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).format(this);
}
//-----------------------------------------------------------------------
......@@ -232,7 +234,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* All other {@code ChronoField} instances will return false.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the field is supported is determined by the field.
*
......@@ -244,7 +246,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
if (field instanceof ChronoField) {
return field == DAY_OF_WEEK;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
......@@ -260,7 +262,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the range can be obtained is determined by the field.
*
......@@ -289,15 +291,13 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
* passing {@code this} as the argument. Whether the value can be obtained,
* and what the value represents, is determined by the field.
*
* @param field the field to get, not null
* @return the value for the field, within the valid range of values
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if the range of valid values for the field exceeds an {@code int}
* @throws DateTimeException if the value is outside the range of valid values for the field
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -320,7 +320,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
* passing {@code this} as the argument. Whether the value can be obtained,
* and what the value represents, is determined by the field.
*
......@@ -336,7 +336,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
......
......@@ -64,11 +64,11 @@ package java.time;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoUnit.MONTHS;
import java.time.chrono.Chronology;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.Chrono;
import java.time.temporal.ChronoField;
import java.time.temporal.ISOChrono;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
......@@ -192,8 +192,9 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
/**
* Obtains an instance of {@code Month} from a temporal object.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code Month}.
* This obtains a month based on the specified temporal.
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
* which this factory converts to an instance of {@code Month}.
* <p>
* The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} field.
* The extraction is only permitted if the temporal object has an ISO
......@@ -211,7 +212,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
return (Month) temporal;
}
try {
if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) {
if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
temporal = LocalDate.from(temporal);
}
return of(temporal.get(MONTH_OF_YEAR));
......@@ -237,8 +238,9 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
/**
* Gets the textual representation, such as 'Jan' or 'December'.
* <p>
* This returns the textual name used to identify the month-of-year.
* The parameters control the length of the returned text and the locale.
* This returns the textual name used to identify the month-of-year,
* suitable for presentation to the user.
* The parameters control the style of the returned text and the locale.
* <p>
* If no textual mapping is found then the {@link #getValue() numeric value} is returned.
*
......@@ -246,8 +248,8 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* @param locale the locale to use, not null
* @return the text value of the month-of-year, not null
*/
public String getText(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(MONTH_OF_YEAR, style).toFormatter(locale).print(this);
public String getDisplayName(TextStyle style, Locale locale) {
return new DateTimeFormatterBuilder().appendText(MONTH_OF_YEAR, style).toFormatter(locale).format(this);
}
//-----------------------------------------------------------------------
......@@ -263,7 +265,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* All other {@code ChronoField} instances will return false.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the field is supported is determined by the field.
*
......@@ -275,7 +277,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
if (field instanceof ChronoField) {
return field == MONTH_OF_YEAR;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
......@@ -291,7 +293,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the range can be obtained is determined by the field.
*
......@@ -320,15 +322,13 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
* passing {@code this} as the argument. Whether the value can be obtained,
* and what the value represents, is determined by the field.
*
* @param field the field to get, not null
* @return the value for the field, within the valid range of values
* @throws DateTimeException if a value for the field cannot be obtained
* @throws DateTimeException if the range of valid values for the field exceeds an {@code int}
* @throws DateTimeException if the value is outside the range of valid values for the field
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
......@@ -351,7 +351,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
* passing {@code this} as the argument. Whether the value can be obtained,
* and what the value represents, is determined by the field.
*
......@@ -367,7 +367,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
} else if (field instanceof ChronoField) {
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
......@@ -554,8 +554,8 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.chrono()) {
return (R) ISOChrono.INSTANCE;
if (query == Queries.chronology()) {
return (R) IsoChronology.INSTANCE;
} else if (query == Queries.precision()) {
return (R) MONTHS;
}
......@@ -599,7 +599,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
*/
@Override
public Temporal adjustInto(Temporal temporal) {
if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) {
if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
throw new DateTimeException("Adjustment only supported on ISO date-time");
}
return temporal.with(MONTH_OF_YEAR, getValue());
......
......@@ -59,7 +59,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java.time.temporal;
package java.time;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
......@@ -70,14 +70,19 @@ import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.time.chrono.Chronology;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.Queries;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.ValueRange;
import java.util.Objects;
/**
......@@ -198,8 +203,8 @@ public final class MonthDay
* @param month the month-of-year to represent, not null
* @param dayOfMonth the day-of-month to represent, from 1 to 31
* @return the month-day, not null
* @throws DateTimeException if the value of any field is out of range
* @throws DateTimeException if the day-of-month is invalid for the month
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-month is invalid for the month
*/
public static MonthDay of(Month month, int dayOfMonth) {
Objects.requireNonNull(month, "month");
......@@ -224,8 +229,8 @@ public final class MonthDay
* @param month the month-of-year to represent, from 1 (January) to 12 (December)
* @param dayOfMonth the day-of-month to represent, from 1 to 31
* @return the month-day, not null
* @throws DateTimeException if the value of any field is out of range
* @throws DateTimeException if the day-of-month is invalid for the month
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-month is invalid for the month
*/
public static MonthDay of(int month, int dayOfMonth) {
return of(Month.of(month), dayOfMonth);
......@@ -235,8 +240,9 @@ public final class MonthDay
/**
* Obtains an instance of {@code MonthDay} from a temporal object.
* <p>
* A {@code TemporalAccessor} represents some form of date and time information.
* This factory converts the arbitrary temporal object to an instance of {@code MonthDay}.
* This obtains a month-day based on the specified temporal.
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
* which this factory converts to an instance of {@code MonthDay}.
* <p>
* The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
* {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields.
......@@ -254,7 +260,7 @@ public final class MonthDay
return (MonthDay) temporal;
}
try {
if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) {
if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
temporal = LocalDate.from(temporal);
}
return of(temporal.get(MONTH_OF_YEAR), temporal.get(DAY_OF_MONTH));
......@@ -314,8 +320,6 @@ public final class MonthDay
* {@link #get(TemporalField) get} methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this date-time.
* The supported fields are:
* <ul>
* <li>{@code MONTH_OF_YEAR}
......@@ -324,7 +328,7 @@ public final class MonthDay
* All other {@code ChronoField} instances will return false.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the field is supported is determined by the field.
*
......@@ -336,7 +340,7 @@ public final class MonthDay
if (field instanceof ChronoField) {
return field == MONTH_OF_YEAR || field == DAY_OF_MONTH;
}
return field != null && field.doIsSupported(this);
return field != null && field.isSupportedBy(this);
}
/**
......@@ -353,7 +357,7 @@ public final class MonthDay
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the range can be obtained is determined by the field.
*
......@@ -385,7 +389,7 @@ public final class MonthDay
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
* passing {@code this} as the argument. Whether the value can be obtained,
* and what the value represents, is determined by the field.
*
......@@ -412,7 +416,7 @@ public final class MonthDay
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
* passing {@code this} as the argument. Whether the value can be obtained,
* and what the value represents, is determined by the field.
*
......@@ -431,10 +435,24 @@ public final class MonthDay
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.doGet(this);
return field.getFrom(this);
}
//-----------------------------------------------------------------------
/**
* Gets the month-of-year field from 1 to 12.
* <p>
* This method returns the month as an {@code int} from 1 to 12.
* Application code is frequently clearer if the enum {@link Month}
* is used by calling {@link #getMonth()}.
*
* @return the month-of-year, from 1 to 12
* @see #getMonth()
*/
public int getMonthValue() {
return month;
}
/**
* Gets the month-of-year field using the {@code Month} enum.
* <p>
......@@ -444,6 +462,7 @@ public final class MonthDay
* provides the {@link Month#getValue() int value}.
*
* @return the month-of-year, not null
* @see #getMonthValue()
*/
public Month getMonth() {
return Month.of(month);
......@@ -524,8 +543,8 @@ public final class MonthDay
*
* @param dayOfMonth the day-of-month to set in the return month-day, from 1 to 31
* @return a {@code MonthDay} based on this month-day with the requested day, not null
* @throws DateTimeException if the day-of-month value is invalid
* @throws DateTimeException if the day-of-month is invalid for the month
* @throws DateTimeException if the day-of-month value is invalid,
* or if the day-of-month is invalid for the month
*/
public MonthDay withDayOfMonth(int dayOfMonth) {
if (dayOfMonth == this.day) {
......@@ -556,8 +575,8 @@ public final class MonthDay
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == Queries.chrono()) {
return (R) ISOChrono.INSTANCE;
if (query == Queries.chronology()) {
return (R) IsoChronology.INSTANCE;
}
return TemporalAccessor.super.query(query);
}
......@@ -591,7 +610,7 @@ public final class MonthDay
*/
@Override
public Temporal adjustInto(Temporal temporal) {
if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) {
if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
throw new DateTimeException("Adjustment only supported on ISO date-time");
}
temporal = temporal.with(MONTH_OF_YEAR, month);
......@@ -600,9 +619,10 @@ public final class MonthDay
//-----------------------------------------------------------------------
/**
* Returns a date formed from this month-day at the specified year.
* Combines this month-day with a year to create a {@code LocalDate}.
* <p>
* This returns a {@code LocalDate} formed from this month-day and the specified year.
* <p>
* This combines this month-day and the specified year to form a {@code LocalDate}.
* A month-day of February 29th will be adjusted to February 28th in the resulting
* date if the year is not a leap year.
* <p>
......@@ -610,7 +630,7 @@ public final class MonthDay
*
* @param year the year to use, from MIN_YEAR to MAX_YEAR
* @return the local date formed from this month-day and the specified year, not null
* @see Year#atMonthDay(MonthDay)
* @throws DateTimeException if the year is outside the valid range of years
*/
public LocalDate atYear(int year) {
return LocalDate.of(year, month, isValidYear(year) ? day : 28);
......@@ -626,6 +646,7 @@ public final class MonthDay
* @param other the other month-day to compare to, not null
* @return the comparator value, negative if less, positive if greater
*/
@Override
public int compareTo(MonthDay other) {
int cmp = (month - other.month);
if (cmp == 0) {
......@@ -705,7 +726,7 @@ public final class MonthDay
* Outputs this month-day as a {@code String} using the formatter.
* <p>
* This month-day will be passed to the formatter
* {@link DateTimeFormatter#print(TemporalAccessor) print method}.
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted month-day string, not null
......@@ -713,7 +734,7 @@ public final class MonthDay
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.print(this);
return formatter.format(this);
}
//-----------------------------------------------------------------------
......@@ -721,7 +742,7 @@ public final class MonthDay
* Writes the object using a
* <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
* <pre>
* out.writeByte(6); // identifies this as a Year
* out.writeByte(13); // identifies this as a MonthDay
* out.writeByte(month);
* out.writeByte(day);
* </pre>
......
此差异已折叠。
......@@ -65,7 +65,7 @@ package java.time.format;
* Enumeration of the style of a localized date, time or date-time formatter.
* <p>
* These styles are used when obtaining a date-time style from configuration.
* See {@link DateTimeFormatters} and {@link DateTimeFormatterBuilder} for usage.
* See {@link DateTimeFormatter} and {@link DateTimeFormatterBuilder} for usage.
*
* <h3>Specification for implementors</h3>
* This is an immutable and thread-safe enum.
......
此差异已折叠。
......@@ -68,7 +68,7 @@
* Printing and parsing is based around the
* {@link java.time.format.DateTimeFormatter DateTimeFormatter} class.
* Instances are generally obtained from
* {@link java.time.format.DateTimeFormatters DateTimeFormatters}, however
* {@link java.time.format.DateTimeFormatter DateTimeFormatter}, however
* {@link java.time.format.DateTimeFormatterBuilder DateTimeFormatterBuilder}
* can be used if more power is needed.
* </p>
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册