[automerger skipped] DO NOT MERGE Use explicitly opened file with O_WRONLY in test_sendfile_errno am: f0324559dd -s ours
am skip reason: subject contains skip directive
Original change: https://android-review.googlesource.com/c/platform/libcore/+/2241795
Change-Id: I73af67ecdb6e1ef0e653c0e533e62c610f798d90
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileTest.java
index 2bf5660..9f397f4 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileTest.java
@@ -410,22 +410,17 @@
// Test create an illegal file
String sep = File.separator;
- f1 = new File(sep + "a" + sep + ".." + sep + ".." + sep);
+ f1 = new File(sep + "..");
try {
f1.createNewFile();
fail("should throw IOE");
} catch (IOException e) {
// expected;
}
-
- // Prior to kernel version 5.7, creating "/.." returns EISDIR, and in 5.7 or later,
- // such syscall returns EEXIST. In the first case, IOException is thrown. In the second
- // case, false is returned. The below test is modified to accept both of them.
- // See http://b/176057454 for details.
- f1 = new File(sep + "..");
+ f1 = new File(sep + "a" + sep + ".." + sep + ".." + sep);
try {
- boolean result = f1.createNewFile();
- assertFalse(result);
+ f1.createNewFile();
+ fail("should throw IOE");
} catch (IOException e) {
// expected;
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java
index 44572ab..96384ad 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java
@@ -40,6 +40,104 @@
assertFalse(hv.verify("localhost", session));
}
+ // copied and modified from apache http client test suite.
+ public void testVerify() throws Exception {
+ HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ InputStream in;
+ X509Certificate x509;
+ // CN=foo.com, no subjectAlt
+ in = new ByteArrayInputStream(X509_FOO);
+ x509 = (X509Certificate) cf.generateCertificate(in);
+ mySSLSession session = new mySSLSession(new X509Certificate[] {x509});
+ assertFalse(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("a.foo.com", session));
+ assertFalse(verifier.verify("bar.com", session));
+
+ // CN=花子.co.jp, no subjectAlt
+ in = new ByteArrayInputStream(X509_HANAKO);
+ x509 = (X509Certificate) cf.generateCertificate(in);
+ session = new mySSLSession(new X509Certificate[] {x509});
+ assertFalse(verifier.verify("\u82b1\u5b50.co.jp", session));
+ assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
+
+ // CN=foo.com, subjectAlt=bar.com
+ in = new ByteArrayInputStream(X509_FOO_BAR);
+ x509 = (X509Certificate) cf.generateCertificate(in);
+ session = new mySSLSession(new X509Certificate[] {x509});
+ assertFalse(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("a.foo.com", session));
+ assertTrue(verifier.verify("bar.com", session));
+ assertFalse(verifier.verify("a.bar.com", session));
+
+ // CN=foo.com, subjectAlt=bar.com, subjectAlt=花子.co.jp
+ in = new ByteArrayInputStream(X509_FOO_BAR_HANAKO);
+ x509 = (X509Certificate) cf.generateCertificate(in);
+ session = new mySSLSession(new X509Certificate[] {x509});
+ assertFalse(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("a.foo.com", session));
+ assertTrue(verifier.verify("bar.com", session));
+ assertFalse(verifier.verify("a.bar.com", session));
+ // The certificate has this name in the altnames section, but OkHostnameVerifier drops
+ // any altnames that are improperly encoded according to RFC 5280, which requires
+ // non-ASCII characters to be encoded in ASCII via Punycode.
+ assertFalse(verifier.verify("\u82b1\u5b50.co.jp", session));
+ assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
+
+ // no CN, subjectAlt=foo.com
+ in = new ByteArrayInputStream(X509_NO_CNS_FOO);
+ x509 = (X509Certificate) cf.generateCertificate(in);
+ session = new mySSLSession(new X509Certificate[] {x509});
+ assertTrue(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("a.foo.com", session));
+
+ // CN=foo.com, CN=bar.com, CN=花子.co.jp, no subjectAlt
+ in = new ByteArrayInputStream(X509_THREE_CNS_FOO_BAR_HANAKO);
+ x509 = (X509Certificate) cf.generateCertificate(in);
+ session = new mySSLSession(new X509Certificate[] {x509});
+ assertFalse(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("a.foo.com", session));
+ assertFalse(verifier.verify("bar.com", session));
+ assertFalse(verifier.verify("a.bar.com", session));
+ assertFalse(verifier.verify("\u82b1\u5b50.co.jp", session));
+ assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
+
+ // CN=*.foo.com, no subjectAlt
+ in = new ByteArrayInputStream(X509_WILD_FOO);
+ x509 = (X509Certificate) cf.generateCertificate(in);
+ session = new mySSLSession(new X509Certificate[] {x509});
+ assertFalse(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("www.foo.com", session));
+ assertFalse(verifier.verify("\u82b1\u5b50.foo.com", session));
+ assertFalse(verifier.verify("a.b.foo.com", session));
+
+ // CN=*.co.jp, no subjectAlt
+ in = new ByteArrayInputStream(X509_WILD_CO_JP);
+ x509 = (X509Certificate) cf.generateCertificate(in);
+ session = new mySSLSession(new X509Certificate[] {x509});
+ assertFalse(verifier.verify("foo.co.jp", session));
+ assertFalse(verifier.verify("\u82b1\u5b50.co.jp", session));
+
+ // CN=*.foo.com, subjectAlt=*.bar.com, subjectAlt=花子.co.jp
+ in = new ByteArrayInputStream(X509_WILD_FOO_BAR_HANAKO);
+ x509 = (X509Certificate) cf.generateCertificate(in);
+ session = new mySSLSession(new X509Certificate[] {x509});
+ // try the foo.com variations
+ assertFalse(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("www.foo.com", session));
+ assertFalse(verifier.verify("\u82b1\u5b50.foo.com", session));
+ assertFalse(verifier.verify("a.b.foo.com", session));
+ assertFalse(verifier.verify("bar.com", session));
+ assertTrue(verifier.verify("www.bar.com", session));
+ assertFalse(verifier.verify("a.b.bar.com", session));
+ // The certificate has this name in the altnames section, but OkHostnameVerifier drops
+ // any altnames that are improperly encoded according to RFC 5280, which requires
+ // non-ASCII characters to be encoded in ASCII via Punycode.
+ assertFalse(verifier.verify("\u82b1\u5b50.bar.com", session));
+ assertFalse(verifier.verify("\u82b1\u5b50.co.jp", session));
+ assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
+ }
+
public void testSubjectAlt() throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(X509_MULTIPLE_SUBJECT_ALT);
diff --git a/luni/src/test/java/libcore/java/net/URLTest.java b/luni/src/test/java/libcore/java/net/URLTest.java
index 1ff9b33..066442e 100644
--- a/luni/src/test/java/libcore/java/net/URLTest.java
+++ b/luni/src/test/java/libcore/java/net/URLTest.java
@@ -582,6 +582,26 @@
assertEquals("http://host/a/c", url.toString()); // RI doesn't canonicalize
}
+ public void testPathContainsBackslash() throws Exception {
+ URL url = new URL("http://host\\path@foo");
+ assertEquals("\\path@foo", url.getPath());
+ assertEquals("host", url.getHost());
+ }
+
+ public void testQueryContainsForwardSlash() throws Exception {
+ URL url = new URL("http://host?query/foo");
+ assertEquals("", url.getPath());
+ assertEquals("host", url.getHost());
+ assertEquals("query/foo", url.getQuery());
+ }
+
+ public void testFragmentContainsForwardSlash() throws Exception {
+ URL url = new URL("http://host#fragment/foo");
+ assertEquals("", url.getPath());
+ assertEquals("host", url.getHost());
+ assertEquals("fragment/foo", url.getRef());
+ }
+
public void testRelativePathAndFragment() throws Exception {
URL base = new URL("http://host/file");
assertEquals("http://host/another#fragment", new URL(base, "another#fragment").toString());
diff --git a/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java b/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
index baa3344..3ea4378 100644
--- a/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
+++ b/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
@@ -156,40 +156,21 @@
}
// http://b/7955614
- public void test_getZoneStrings_Apia() {
+ public void test_getZoneStrings_Apia() throws Exception {
String[][] array = DateFormatSymbols.getInstance(Locale.US).getZoneStrings();
-
for (int i = 0; i < array.length; ++i) {
String[] row = array[i];
// Pacific/Apia is somewhat arbitrary; we just want a zone we have to generate
// "GMT" strings for the short names.
if (row[0].equals("Pacific/Apia")) {
- TimeZone apiaTz = TimeZone.getTimeZone("Pacific/Apia");
assertEquals("Apia Standard Time", row[1]);
- assertEquals(formattedStandardTimeOffset(apiaTz), row[2]);
+ assertEquals("GMT+13:00", row[2]);
assertEquals("Apia Daylight Time", row[3]);
- assertEquals(formattedDstOffset(apiaTz), row[4]);
+ assertEquals("GMT+14:00", row[4]);
}
}
}
- private static String formattedStandardTimeOffset(TimeZone tz) {
- return formattedOffset(tz.getRawOffset());
- }
-
- private static String formattedDstOffset(TimeZone tz) {
- return formattedOffset(tz.getRawOffset() + tz.getDSTSavings());
- }
-
- private static String formattedOffset(int offset) {
- String pattern = "GMT%+d:%02d";
- int millisInHour = 60 * 60 * 1_000;
- int hours = offset / millisInHour;
- int minutes = (offset - hours * millisInHour) / 1_000 / 60;
-
- return String.format(pattern, hours, minutes);
- }
-
public void test_setZoneStrings_checks_dimensions() throws Exception {
DateFormatSymbols dfs = DateFormatSymbols.getInstance();
String[][] zoneStrings = dfs.getZoneStrings();
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 10baadc..bf4c8e0 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -84,10 +84,7 @@
public void testGetDisplayNameShort_nonHourOffsets() {
TimeZone iranTz = TimeZone.getTimeZone("Asia/Tehran");
assertEquals("GMT+03:30", iranTz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
-
- TimeZone chathamTz = TimeZone.getTimeZone("Pacific/Chatham");
- assertEquals("GMT+12:45", chathamTz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
- assertEquals("GMT+13:45", chathamTz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
+ assertEquals("GMT+04:30", iranTz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
}
public void testPreHistoricOffsets() throws Exception {
@@ -317,16 +314,12 @@
}
// http://b/7955614
- public void testApia() {
+ public void testApia() throws Exception {
TimeZone tz = TimeZone.getTimeZone("Pacific/Apia");
assertEquals("Apia Daylight Time", tz.getDisplayName(true, TimeZone.LONG, Locale.US));
assertEquals("Apia Standard Time", tz.getDisplayName(false, TimeZone.LONG, Locale.US));
-
- long samoaStandardTime = 1630315635000L; // 30 Aug 2021
- long samoaDst = 1614504435000L; // 28 Feb 2021
-
- assertEquals(13 * 60 * 60 * 1_000, tz.getOffset(samoaStandardTime));
- assertEquals(14 * 60 * 60 * 1_000, tz.getOffset(samoaDst));
+ assertEquals("GMT+14:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.US));
+ assertEquals("GMT+13:00", tz.getDisplayName(false, TimeZone.SHORT, Locale.US));
}
private static boolean isGmtString(String s) {
diff --git a/luni/src/test/java/libcore/libcore/io/OsTest.java b/luni/src/test/java/libcore/libcore/io/OsTest.java
index a9233ca..5e8a691 100644
--- a/luni/src/test/java/libcore/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/libcore/io/OsTest.java
@@ -841,18 +841,12 @@
// http://b/65051835
public void test_sendfile_errno() throws Exception {
- File testFile = File.createTempFile("test_sendfile_errno", "");
- FileDescriptor fd = Libcore.os.open(testFile.toString(), O_WRONLY, S_IRUSR | S_IWUSR);
- assertNotNull(fd);
-
try {
- // fd is not open for input, will cause EBADF
+ // FileDescriptor.out is not open for input, will cause EBADF
Int64Ref offset = new Int64Ref(10);
- Libcore.os.sendfile(fd, fd, offset, 10);
+ Libcore.os.sendfile(FileDescriptor.out, FileDescriptor.out, offset, 10);
fail();
} catch(ErrnoException expected) {
- } finally {
- Libcore.os.close(fd);
}
}
diff --git a/ojluni/src/main/java/java/net/URLStreamHandler.java b/ojluni/src/main/java/java/net/URLStreamHandler.java
index d5380c1..01862f6 100644
--- a/ojluni/src/main/java/java/net/URLStreamHandler.java
+++ b/ojluni/src/main/java/java/net/URLStreamHandler.java
@@ -167,12 +167,25 @@
if (!isUNCName && (start <= limit - 2) && (spec.charAt(start) == '/') &&
(spec.charAt(start + 1) == '/')) {
start += 2;
+ // BEGIN Android-changed: Check for all hostname termination chars. http://b/110955991
+ /*
i = spec.indexOf('/', start);
if (i < 0 || i > limit) {
i = spec.indexOf('?', start);
if (i < 0 || i > limit)
i = limit;
}
+ */
+ LOOP: for (i = start; i < limit; i++) {
+ switch (spec.charAt(i)) {
+ case '/': // Start of path
+ case '\\': // Start of path - see https://url.spec.whatwg.org/#host-state
+ case '?': // Start of query
+ case '#': // Start of fragment
+ break LOOP;
+ }
+ }
+ // END Android-changed: Check for all hostname termination chars. http://b/110955991
host = authority = spec.substring(start, i);
@@ -266,7 +279,9 @@
// Parse the file path if any
if (start < limit) {
- if (spec.charAt(start) == '/') {
+ // Android-changed: Check for all hostname termination chars. http://b/110955991
+ // if (spec.charAt(start) == '/') {
+ if (spec.charAt(start) == '/' || spec.charAt(start) == '\\') {
path = spec.substring(start, limit);
} else if (path != null && path.length() > 0) {
isRelPath = true;
diff --git a/ojluni/src/main/java/java/time/chrono/JapaneseEra.java b/ojluni/src/main/java/java/time/chrono/JapaneseEra.java
index 0c9e3e8..d52f3c1 100644
--- a/ojluni/src/main/java/java/time/chrono/JapaneseEra.java
+++ b/ojluni/src/main/java/java/time/chrono/JapaneseEra.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -73,11 +73,14 @@
import java.io.Serializable;
import java.time.DateTimeException;
import java.time.LocalDate;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalField;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.Arrays;
+import java.util.Locale;
import java.util.Objects;
import sun.util.calendar.CalendarDate;
@@ -85,10 +88,33 @@
/**
* An era in the Japanese Imperial calendar system.
* <p>
- * This class defines the valid eras for the Japanese chronology.
- * Japan introduced the Gregorian calendar starting with Meiji 6.
- * Only Meiji and later eras are supported;
- * dates before Meiji 6, January 1 are not supported.
+ * The Japanese government defines the official name and start date of
+ * each era. Eras are consecutive and their date ranges do not overlap,
+ * so the end date of one era is always the day before the start date
+ * of the next era.
+ * <p>
+ * The Java SE Platform supports all eras defined by the Japanese government,
+ * beginning with the Meiji era. Each era is identified in the Platform by an
+ * integer value and a name. The {@link #of(int)} and {@link #valueOf(String)}
+ * methods may be used to obtain a singleton instance of JapaneseEra for each
+ * era. The {@link #values()} method returns the singleton instances of all
+ * supported eras.
+ * <p>
+ * For convenience, this class declares a number of public static final fields
+ * that refer to singleton instances returned by the values() method.
+ *
+ * @apiNote
+ * The fields declared in this class may evolve over time, in line with the
+ * results of the {@link #values()} method. However, there is not necessarily
+ * a 1:1 correspondence between the fields and the singleton instances.
+ *
+ * @apiNote
+ * The Japanese government may announce a new era and define its start
+ * date but not its official name. In this scenario, the singleton instance
+ * that represents the new era may return a name that is not stable until
+ * the official name is defined. Developers should exercise caution when
+ * relying on the name returned by any singleton instance that does not
+ * correspond to a public static final field.
*
* @implSpec
* This class is immutable and thread-safe.
@@ -120,14 +146,20 @@
*/
public static final JapaneseEra SHOWA = new JapaneseEra(1, LocalDate.of(1926, 12, 25));
/**
- * The singleton instance for the 'Heisei' era (1989-01-08 - current)
+ * The singleton instance for the 'Heisei' era (1989-01-08 - 2019-04-30)
* which has the value 2.
*/
public static final JapaneseEra HEISEI = new JapaneseEra(2, LocalDate.of(1989, 1, 8));
+ /**
+ * The singleton instance for the 'Reiwa' era (2019-05-01 - current)
+ * which has the value 3. The end date of this era is not specified, unless
+ * the Japanese Government defines it.
+ */
+ private static final JapaneseEra REIWA = new JapaneseEra(3, LocalDate.of(2019, 5, 1));
- // the number of defined JapaneseEra constants.
- // There could be an extra era defined in its configuration.
- private static final int N_ERA_CONSTANTS = HEISEI.getValue() + ERA_OFFSET;
+ // The number of predefined JapaneseEra constants.
+ // There may be a supplemental era defined by the property.
+ private static final int N_ERA_CONSTANTS = REIWA.getValue() + ERA_OFFSET;
/**
* Serialization version.
@@ -145,6 +177,7 @@
KNOWN_ERAS[1] = TAISHO;
KNOWN_ERAS[2] = SHOWA;
KNOWN_ERAS[3] = HEISEI;
+ KNOWN_ERAS[4] = REIWA;
for (int i = N_ERA_CONSTANTS; i < ERA_CONFIG.length; i++) {
CalendarDate date = ERA_CONFIG[i].getSinceDate();
LocalDate isoDate = LocalDate.of(date.getYear(), date.getMonth(), date.getDayOfMonth());
@@ -185,10 +218,18 @@
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code JapaneseEra} from an {@code int} value.
+ * <ul>
+ * <li>The value {@code 1} is associated with the 'Showa' era, because
+ * it contains 1970-01-01 (ISO calendar system).</li>
+ * <li>The values {@code -1} and {@code 0} are associated with two earlier
+ * eras, Meiji and Taisho, respectively.</li>
+ * <li>A value greater than {@code 1} is associated with a later era,
+ * beginning with Heisei ({@code 2}).</li>
+ * </ul>
* <p>
- * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1
- * Later era is numbered 2 ({@link #HEISEI}). Earlier eras are numbered 0 ({@link #TAISHO}),
- * -1 ({@link #MEIJI}), only Meiji and later eras are supported.
+ * Every instance of {@code JapaneseEra} that is returned from the {@link #values()}
+ * method has an int value (available via {@link Era#getValue()} which is
+ * accepted by this method.
*
* @param japaneseEra the era to represent
* @return the {@code JapaneseEra} singleton, not null
@@ -236,6 +277,28 @@
return Arrays.copyOf(KNOWN_ERAS, KNOWN_ERAS.length);
}
+ /**
+ * {@inheritDoc}
+ *
+ * @param style {@inheritDoc}
+ * @param locale {@inheritDoc}
+ */
+ @Override
+ public String getDisplayName(TextStyle style, Locale locale) {
+ // If this JapaneseEra is a supplemental one, obtain the name from
+ // the era definition.
+ if (getValue() > N_ERA_CONSTANTS - ERA_OFFSET) {
+ Objects.requireNonNull(locale, "locale");
+ return style.asNormal() == TextStyle.NARROW ? getAbbreviation() : getName();
+ }
+
+ return new DateTimeFormatterBuilder()
+ .appendText(ERA, style)
+ .toFormatter(locale)
+ .withChronology(JapaneseChronology.INSTANCE)
+ .format(this == MEIJI ? MEIJI_6_ISODATE : since);
+ }
+
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code JapaneseEra} from a date.
@@ -337,11 +400,7 @@
//-----------------------------------------------------------------------
String getAbbreviation() {
- int index = ordinal(getValue());
- if (index == 0) {
- return "";
- }
- return ERA_CONFIG[index].getAbbreviation();
+ return ERA_CONFIG[ordinal(getValue())].getAbbreviation();
}
String getName() {
diff --git a/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java b/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java
index c569981..9bca22a 100644
--- a/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java
+++ b/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, 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
@@ -49,6 +49,7 @@
* 2 Taisho 1912-07-30 midnight local time
* 3 Showa 1926-12-25 midnight local time
* 4 Heisei 1989-01-08 midnight local time
+ * 5 Reiwa 2019-05-01 midnight local time
* ------------------------------------------------------
* </tt></pre>
*
@@ -100,6 +101,11 @@
*/
public static final int HEISEI = 4;
+ /**
+ * The ERA constant designating the Reiwa era.
+ */
+ private static final int REIWA = 5;
+
private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian)
private static final int EPOCH_YEAR = 1970;
@@ -132,6 +138,9 @@
// Fixed date of the first date of each era.
private static final long[] sinceFixedDates;
+ // The current era
+ private static final int currentEra;
+
/*
* <pre>
* Greatest Least
@@ -227,13 +236,25 @@
// eras[BEFORE_MEIJI] and sinceFixedDate[BEFORE_MEIJI] are the
// same as Gregorian.
int index = BEFORE_MEIJI;
+ // Android-removed: Zygote could initialize this class when system has outdated time.
+ // int current = index;
sinceFixedDates[index] = gcal.getFixedDate(BEFORE_MEIJI_ERA.getSinceDate());
eras[index++] = BEFORE_MEIJI_ERA;
for (Era e : es) {
+ // Android-removed: Zygote could initialize this class when system has outdated time.
+ // Android hard-code the current era. Unlike upstream, Android does not add the new era
+ // in the code until the new era arrives. Thus, Android can't have newer era than the
+ // real world. currentEra is the latest Era that Android knows about.
+ // if(e.getSince(TimeZone.NO_TIMEZONE) < System.currentTimeMillis()) {
+ // current = index;
+ // }
CalendarDate d = e.getSinceDate();
sinceFixedDates[index] = gcal.getFixedDate(d);
eras[index++] = e;
}
+ // Android-changed: Zygote could initialize this class when system has outdated time.
+ // currentEra = current;
+ currentEra = REIWA;
LEAST_MAX_VALUES[ERA] = MAX_VALUES[ERA] = eras.length - 1;
@@ -1713,12 +1734,12 @@
}
} else if (transitionYear) {
if (jdate.getYear() == 1) {
- // As of Heisei (since Meiji) there's no case
+ // As of Reiwa (since Meiji) there's no case
// that there are multiple transitions in a
// year. Historically there was such
// case. There might be such case again in the
// future.
- if (era > HEISEI) {
+ if (era > REIWA) {
CalendarDate pd = eras[era - 1].getSinceDate();
if (normalizedYear == pd.getYear()) {
d.setMonth(pd.getMonth()).setDayOfMonth(pd.getDayOfMonth());
@@ -1853,7 +1874,7 @@
year = isSet(YEAR) ? internalGet(YEAR) : 1;
} else {
if (isSet(YEAR)) {
- era = eras.length - 1;
+ era = currentEra;
year = internalGet(YEAR);
} else {
// Equivalent to 1970 (Gregorian)
@@ -2338,7 +2359,7 @@
* default ERA is the current era, but a zero (unset) ERA means before Meiji.
*/
private int internalGetEra() {
- return isSet(ERA) ? internalGet(ERA) : eras.length - 1;
+ return isSet(ERA) ? internalGet(ERA) : currentEra;
}
/**
diff --git a/ojluni/src/main/java/java/util/Locale.java b/ojluni/src/main/java/java/util/Locale.java
index c96bb13..434922a 100644
--- a/ojluni/src/main/java/java/util/Locale.java
+++ b/ojluni/src/main/java/java/util/Locale.java
@@ -520,7 +520,7 @@
* <td><a href="http://site.icu-project.org/download/58">ICU 58.2</a></td>
* <td><a href="http://cldr.unicode.org/index/downloads/cldr-30">CLDR 30.0.3</a></td>
* <td><a href="http://www.unicode.org/versions/Unicode9.0.0/">Unicode 9.0</a></td></tr>
- * <tr><td>Android 9.0 (TBD)</td>
+ * <tr><td>Android 9.0 (Pie)</td>
* <td><a href="http://site.icu-project.org/download/60">ICU 60.2</a></td>
* <td><a href="http://cldr.unicode.org/index/downloads/cldr-32">CLDR 32.0.1</a></td>
* <td><a href="http://www.unicode.org/versions/Unicode10.0.0/">Unicode 10.0</a></td></tr>
diff --git a/ojluni/src/main/java/sun/util/calendar/Era.java b/ojluni/src/main/java/sun/util/calendar/Era.java
index a013c57..7c02cce 100644
--- a/ojluni/src/main/java/sun/util/calendar/Era.java
+++ b/ojluni/src/main/java/sun/util/calendar/Era.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -49,6 +49,7 @@
* Taisho 1912-07-30 midnight local time
* Showa 1926-12-26 midnight local time
* Heisei 1989-01-08 midnight local time
+ * Reiwa 2019-05-01 midnight local time
* Julian calendar BeforeCommonEra -292275055-05-16T16:47:04.192Z
* CommonEra 0000-12-30 midnight local time
* Taiwanese calendar MinGuo 1911-01-01 midnight local time
diff --git a/ojluni/src/main/resources/calendars.properties b/ojluni/src/main/resources/calendars.properties
index 49f68ac..6007d7a 100644
--- a/ojluni/src/main/resources/calendars.properties
+++ b/ojluni/src/main/resources/calendars.properties
@@ -29,12 +29,14 @@
# Taisho since 1912-07-30 00:00:00 local time (Gregorian)
# Showa since 1926-12-25 00:00:00 local time (Gregorian)
# Heisei since 1989-01-08 00:00:00 local time (Gregorian)
+# Reiwa since 2019-05-01 00:00:00 local time (Gregorian)
calendar.japanese.type: LocalGregorianCalendar
calendar.japanese.eras: \
name=Meiji,abbr=M,since=-3218832000000; \
name=Taisho,abbr=T,since=-1812153600000; \
name=Showa,abbr=S,since=-1357603200000; \
- name=Heisei,abbr=H,since=600220800000
+ name=Heisei,abbr=H,since=600220800000; \
+ name=Reiwa,abbr=R,since=1556668800000
#
# Taiwanese calendar