Merge "[automerger skipped] Merge "[RESTRICT AUTOMERGE] Track behavior change in default HostnameVerifier." into oreo-mr1-cts-dev am: e79d676601 -s ours" into pie-cts-dev am: f79b99d030 -s ours

am skip reason: subject contains skip directive

Original change: https://android-review.googlesource.com/c/platform/libcore/+/1547918

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Id28cb4e0b2ac31f08bd272956f7c7e054692571a
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/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