[Git][java-team/icu4j][upstream] New upstream version 62.2

Emmanuel Bourg gitlab at salsa.debian.org
Tue Jan 5 14:48:48 GMT 2021



Emmanuel Bourg pushed to branch upstream at Debian Java Maintainers / icu4j


Commits:
7ac9cf3e by Emmanuel Bourg at 2021-01-05T14:18:01+01:00
New upstream version 62.2
- - - - -


22 changed files:

- − .gitignore
- build.properties
- build.xml
- eclipse-build/build.properties
- + main/classes/core/src/com/ibm/icu/impl/CalType.java
- + main/classes/core/src/com/ibm/icu/impl/EraRules.java
- main/classes/core/src/com/ibm/icu/impl/UCaseProps.java
- main/classes/core/src/com/ibm/icu/util/Calendar.java
- main/classes/core/src/com/ibm/icu/util/JapaneseCalendar.java
- main/classes/core/src/com/ibm/icu/util/VersionInfo.java
- main/shared/build/common.properties
- main/shared/data/icudata.jar
- main/shared/data/icutzdata.jar
- main/shared/data/testdata.jar
- + main/tests/core/src/com/ibm/icu/dev/test/calendar/EraRulesTest.java
- main/tests/core/src/com/ibm/icu/dev/test/calendar/JapaneseTest.java
- main/tests/core/src/com/ibm/icu/dev/test/lang/UCharacterCaseTest.java
- main/tests/core/src/com/ibm/icu/dev/test/util/DebugUtilitiesData.java
- maven/icu4j-charset/pom.xml
- maven/icu4j-localespi/pom.xml
- maven/icu4j/pom.xml
- readme.html


Changes:

=====================================
.gitignore deleted
=====================================
@@ -1,17 +0,0 @@
-# Copyright (C) 2016 and later: Unicode, Inc. and others.
-# License & terms of use: http://www.unicode.org/copyright.html
-/*.jar
-/.project
-/build-local.properties
-/demos/out
-/doc
-/eclipse-build/out
-/lib/*.jar
-/main/*/out
-out
-perf-tests/out
-samples/out
-tools/build/out
-tools/misc/out
-*.jar
-!main/shared/data/*.jar


=====================================
build.properties
=====================================
@@ -6,6 +6,6 @@
 #*******************************************************************************
 api.report.version = 62
 api.report.prev.version = 61
-release.file.ver = 62_1
-api.doc.version = 62.1
-maven.pom.ver = 62.1
+release.file.ver = 62_2
+api.doc.version = 62.2
+maven.pom.ver = 62.2


=====================================
build.xml
=====================================
@@ -57,7 +57,7 @@
     <property name="icu4j.api.doc.window.title" value="ICU4J ${api.doc.version}"/>
     <property name="icu4j.api.doc.header" value="ICU4J ${api.doc.version}"/>
 
-    <property name="icu4j.api.doc.jdk.link" value="http://docs.oracle.com/javase/8/docs/api/"/>
+    <property name="icu4j.api.doc.jdk.link" value="https://docs.oracle.com/javase/8/docs/api/"/>
     <property name="icu4j.api.doc.copyright.footer" value="<font size=-1>Copyright &#x00A9; 2016 Unicode, Inc. and others.</font>"/>
 
     <!-- API docs for maven repo -->


=====================================
eclipse-build/build.properties
=====================================
@@ -4,6 +4,6 @@
 #* Copyright (C) 2010-2016, International Business Machines Corporation and    *
 #* others. All Rights Reserved.                                                *
 #*******************************************************************************
-icu4j.plugin.impl.version.string=62.1.0
+icu4j.plugin.impl.version.string=62.2.0
 copyright.eclipse=(C) 2016 and later: Unicode, Inc. and others. License & terms of use: http://www.unicode.org/copyright.html#License
 icu4j.data.version.number=62


=====================================
main/classes/core/src/com/ibm/icu/impl/CalType.java
=====================================
@@ -0,0 +1,42 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.impl;
+
+/**
+ * Calendar type enum, moved from com.ibm.icu.util.Calendar.
+ *
+ * @author Yoshito Umaoka
+ */
+public enum CalType {
+    GREGORIAN("gregorian"),
+    ISO8601("iso8601"),
+
+    BUDDHIST("buddhist"),
+    CHINESE("chinese"),
+    COPTIC("coptic"),
+    DANGI("dangi"),
+    ETHIOPIC("ethiopic"),
+    ETHIOPIC_AMETE_ALEM("ethiopic-amete-alem"),
+    HEBREW("hebrew"),
+    INDIAN("indian"),
+    ISLAMIC("islamic"),
+    ISLAMIC_CIVIL("islamic-civil"),
+    ISLAMIC_RGSA("islamic-rgsa"),
+    ISLAMIC_TBLA("islamic-tbla"),
+    ISLAMIC_UMALQURA("islamic-umalqura"),
+    JAPANESE("japanese"),
+    PERSIAN("persian"),
+    ROC("roc"),
+
+    UNKNOWN("unknown");
+
+    String id;
+
+    CalType(String id) {
+        this.id = id;
+    }
+
+    public String getId() {
+        return id;
+    }
+}


=====================================
main/classes/core/src/com/ibm/icu/impl/EraRules.java
=====================================
@@ -0,0 +1,309 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.impl;
+
+import java.util.Arrays;
+
+import com.ibm.icu.util.ICUException;
+import com.ibm.icu.util.UResourceBundle;
+import com.ibm.icu.util.UResourceBundleIterator;
+
+/**
+ * <code>EraRules</code> represents calendar era rules specified
+ * in supplementalData/calendarData.
+ *
+ * @author Yoshito Umaoka
+ */
+public class EraRules {
+    private static final int MAX_ENCODED_START_YEAR = 32767;
+    private static final int MIN_ENCODED_START_YEAR = -32768;
+
+    public static final int MIN_ENCODED_START = encodeDate(MIN_ENCODED_START_YEAR, 1, 1);
+
+    private static final int YEAR_MASK = 0xFFFF0000;
+    private static final int MONTH_MASK = 0x0000FF00;
+    private static final int DAY_MASK = 0x000000FF;
+
+    private int[] startDates;
+    private int numEras;
+    private int currentEra;
+
+    private EraRules(int[] startDates, int numEras) {
+        this.startDates = startDates;
+        this.numEras = numEras;
+        initCurrentEra();
+    }
+
+    public static EraRules getInstance(CalType calType, boolean includeTentativeEra) {
+        UResourceBundle supplementalDataRes = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME,
+                "supplementalData", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
+        UResourceBundle calendarDataRes = supplementalDataRes.get("calendarData");
+        UResourceBundle calendarTypeRes = calendarDataRes.get(calType.getId());
+        UResourceBundle erasRes = calendarTypeRes.get("eras");
+
+        int numEras = erasRes.getSize();
+        int firstTentativeIdx = Integer.MAX_VALUE; // first tentative era index
+        int[] startDates = new int[numEras];
+
+        UResourceBundleIterator itr = erasRes.getIterator();
+        while (itr.hasNext()) {
+            UResourceBundle eraRuleRes = itr.next();
+            String eraIdxStr = eraRuleRes.getKey();
+            int eraIdx = -1;
+            try {
+                eraIdx = Integer.parseInt(eraIdxStr);
+            } catch (NumberFormatException e) {
+                throw new ICUException("Invald era rule key:" + eraIdxStr + " in era rule data for " + calType.getId());
+            }
+            if (eraIdx < 0 || eraIdx >= numEras) {
+                throw new ICUException("Era rule key:" + eraIdxStr + " in era rule data for " + calType.getId()
+                        + " must be in range [0, " + (numEras - 1) + "]");
+            }
+            if (isSet(startDates[eraIdx])) {
+                throw new ICUException(
+                        "Dupulicated era rule for rule key:" + eraIdxStr + " in era rule data for " + calType.getId());
+            }
+
+            boolean hasName = true;
+            boolean hasEnd = false;
+            UResourceBundleIterator ruleItr = eraRuleRes.getIterator();
+            while (ruleItr.hasNext()) {
+                UResourceBundle res = ruleItr.next();
+                String key = res.getKey();
+                if (key.equals("start")) {
+                    int[] fields = res.getIntVector();
+                    if (fields.length != 3 || !isValidRuleStartDate(fields[0], fields[1], fields[2])) {
+                        throw new ICUException(
+                                "Invalid era rule date data:" + Arrays.toString(fields) + " in era rule data for "
+                                + calType.getId());
+                    }
+                    startDates[eraIdx] = encodeDate(fields[0], fields[1], fields[2]);
+                } else if (key.equals("named")) {
+                    String val = res.getString();
+                    if (val.equals("false")) {
+                        hasName = false;
+                    }
+                } else if (key.equals("end")) {
+                    hasEnd = true;
+                }
+            }
+            if (isSet(startDates[eraIdx])) {
+                if (hasEnd) {
+                    // This implementation assumes either start or end is available, not both.
+                    // For now, just ignore the end rule.
+                }
+            } else {
+                if (hasEnd) {
+                    if (eraIdx != 0) {
+                        // This implementation does not support end only rule for eras other than
+                        // the first one.
+                        throw new ICUException(
+                                "Era data for " + eraIdxStr + " in era rule data for " + calType.getId()
+                                + " has only end rule.");
+                    }
+                    startDates[eraIdx] = MIN_ENCODED_START;
+                } else {
+                    throw new ICUException("Missing era start/end rule date for key:" + eraIdxStr + " in era rule data for "
+                            + calType.getId());
+                }
+            }
+
+            if (hasName) {
+                if (eraIdx >= firstTentativeIdx) {
+                    throw new ICUException(
+                            "Non-tentative era(" + eraIdx + ") must be placed before the first tentative era");
+                }
+            } else {
+                if (eraIdx < firstTentativeIdx) {
+                    firstTentativeIdx = eraIdx;
+                }
+            }
+        }
+
+        if (firstTentativeIdx < Integer.MAX_VALUE && !includeTentativeEra) {
+            return new EraRules(startDates, firstTentativeIdx);
+        }
+
+        return new EraRules(startDates, numEras);
+    }
+
+    /**
+     * Gets number of effective eras
+     * @return  number of effective eras
+     */
+    public int getNumberOfEras() {
+        return numEras;
+    }
+
+    /**
+     * Gets start date of an era
+     * @param eraIdx    Era index
+     * @param fillIn    Receives date fields if supplied. If null, or size of array
+     *                  is less than 3, then a new int[] will be newly allocated.
+     * @return  An int array including values of year, month, day of month in this order.
+     *          When an era has no start date, the result will be January 1st in year
+     *          whose value is minimum integer.
+     */
+    public int[] getStartDate(int eraIdx, int[] fillIn) {
+        if (eraIdx < 0 || eraIdx >= numEras) {
+            throw new IllegalArgumentException("eraIdx is out of range");
+        }
+        return decodeDate(startDates[eraIdx], fillIn);
+    }
+
+    /**
+     * Gets start year of an era
+     * @param eraIdx    Era index
+     * @return  The first year of an era. When a era has no start date, minimum integer
+     *          value is returned.
+     */
+    public int getStartYear(int eraIdx) {
+        if (eraIdx < 0 || eraIdx >= numEras) {
+            throw new IllegalArgumentException("eraIdx is out of range");
+        }
+        int[] fields = decodeDate(startDates[eraIdx], null);
+        return fields[0];
+    }
+
+    /**
+     * Returns era index for the specified year/month/day.
+     * @param year  Year
+     * @param month Month (1-base)
+     * @param day   Day of month
+     * @return  era index (or 0, when the specified date is before the first era)
+     */
+    public int getEraIndex(int year, int month, int day) {
+        if (month < 1 || month > 12 || day < 1 || day > 31) {
+            throw new IllegalArgumentException("Illegal date - year:" + year + "month:" + month + "day:" + day);
+        }
+        int high = numEras; // last index + 1
+        int low;
+
+        // Short circuit for recent years.  Most modern computations will
+        // occur in the last few eras.
+        if (compareEncodedDateWithYMD(startDates[getCurrentEraIndex()], year, month, day) <= 0) {
+            low = getCurrentEraIndex();
+        } else {
+            low = 0;
+        }
+
+        // Do binary search
+        while (low < high - 1) {
+            int i = (low + high) / 2;
+            if (compareEncodedDateWithYMD(startDates[i], year, month, day) <= 0) {
+                low = i;
+            } else {
+                high = i;
+            }
+        }
+        return low;
+    }
+
+    /**
+     * Gets the current era index. This is calculated only once for an instance of
+     * EraRules.
+     *
+     * @return era index of current era (or 0, when current date is before the first era)
+     */
+    public int getCurrentEraIndex() {
+        return currentEra;
+    }
+
+    private void initCurrentEra() {
+        int[] fields = Grego.timeToFields(System.currentTimeMillis(), null);
+        int currentEncodedDate = encodeDate(fields[0], fields[1] + 1 /* changes to 1-base */, fields[2]);
+        int eraIdx = numEras - 1;
+        while (eraIdx > 0) {
+            if (currentEncodedDate >= startDates[eraIdx]) {
+                break;
+            }
+            eraIdx--;
+        }
+        // Note: current era could be before the first era.
+        // In this case, this implementation returns the first era index (0).
+        currentEra = eraIdx;
+    }
+
+    //
+    // private methods
+    //
+
+    private static boolean isSet(int startDate) {
+        return startDate != 0;
+    }
+
+    private static boolean isValidRuleStartDate(int year, int month, int day) {
+        return year >= MIN_ENCODED_START_YEAR && year <= MAX_ENCODED_START_YEAR
+                && month >= 1 && month <= 12 && day >= 1 && day <= 31;
+    }
+
+    /**
+     * Encode year/month/date to a single integer.
+     * year is high 16 bits (-32768 to 32767), month is
+     * next 8 bits and day of month is last 8 bits.
+     *
+     * @param year  year
+     * @param month month (1-base)
+     * @param day   day of month
+     * @return  an encoded date.
+     */
+    private static int encodeDate(int year, int month, int day) {
+        return year << 16 | month << 8 | day;
+    }
+
+    private static int[] decodeDate(int encodedDate, int[] fillIn) {
+        int year, month, day;
+        if (encodedDate == MIN_ENCODED_START) {
+            year = Integer.MIN_VALUE;
+            month = 1;
+            day = 1;
+        } else {
+            year = (encodedDate & YEAR_MASK) >> 16;
+            month = (encodedDate & MONTH_MASK) >> 8;
+            day = encodedDate & DAY_MASK;
+        }
+
+        if (fillIn != null && fillIn.length >= 3) {
+            fillIn[0] = year;
+            fillIn[1] = month;
+            fillIn[2] = day;
+            return fillIn;
+        }
+
+        int[] result = {year, month, day};
+        return result;
+    }
+
+    /**
+     * Compare an encoded date with another date specified by year/month/day.
+     * @param encoded   An encoded date
+     * @param year      Year of another date
+     * @param month     Month of another date
+     * @param day       Day of another date
+     * @return -1 when encoded date is earlier, 0 when two dates are same,
+     *          and 1 when encoded date is later.
+     */
+    private static int compareEncodedDateWithYMD(int encoded, int year, int month, int day) {
+        if (year < MIN_ENCODED_START_YEAR) {
+            if (encoded == MIN_ENCODED_START) {
+                if (year > Integer.MIN_VALUE || month > 1 || day > 1) {
+                    return -1;
+                }
+                return 0;
+            } else {
+                return 1;
+            }
+        } else if (year > MAX_ENCODED_START_YEAR) {
+            return -1;
+        } else {
+            int tmp = encodeDate(year, month, day);
+            if (encoded < tmp) {
+                return -1;
+            } else if (encoded == tmp) {
+                return 0;
+            } else {
+                return 1;
+            }
+        }
+    }
+}
\ No newline at end of file


=====================================
main/classes/core/src/com/ibm/icu/impl/UCaseProps.java
=====================================
@@ -318,6 +318,7 @@ public final class UCaseProps {
                 }
             }
             if(hasSlot(excWord, EXC_DELTA)) {
+                excOffset=excOffset0;
                 int delta=getSlotValue(excWord, EXC_DELTA, excOffset);
                 set.add((excWord&EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta);
             }
@@ -1131,7 +1132,7 @@ public final class UCaseProps {
             }
 
             if(hasSlot(excWord, EXC_DELTA) && isUpperOrTitleFromProps(props)) {
-                int delta=getSlotValue(excWord, EXC_DELTA, excOffset);
+                int delta=getSlotValue(excWord, EXC_DELTA, excOffset2);
                 return (excWord&EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta;
             }
             if(hasSlot(excWord, EXC_LOWER)) {
@@ -1227,7 +1228,7 @@ public final class UCaseProps {
             }
 
             if(hasSlot(excWord, EXC_DELTA) && getTypeFromProps(props)==LOWER) {
-                int delta=getSlotValue(excWord, EXC_DELTA, excOffset);
+                int delta=getSlotValue(excWord, EXC_DELTA, excOffset2);
                 return (excWord&EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta;
             }
             if(!upperNotTitle && hasSlot(excWord, EXC_TITLE)) {
@@ -1448,7 +1449,7 @@ public final class UCaseProps {
                 return ~c;
             }
             if(hasSlot(excWord, EXC_DELTA) && isUpperOrTitleFromProps(props)) {
-                int delta=getSlotValue(excWord, EXC_DELTA, excOffset);
+                int delta=getSlotValue(excWord, EXC_DELTA, excOffset2);
                 return (excWord&EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta;
             }
             if(hasSlot(excWord, EXC_FOLD)) {


=====================================
main/classes/core/src/com/ibm/icu/util/Calendar.java
=====================================
@@ -17,6 +17,7 @@ import java.util.Date;
 import java.util.Locale;
 import java.util.MissingResourceException;
 
+import com.ibm.icu.impl.CalType;
 import com.ibm.icu.impl.CalendarUtil;
 import com.ibm.icu.impl.ICUCache;
 import com.ibm.icu.impl.ICUData;
@@ -1780,42 +1781,12 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
         return region;
     }
 
-    private enum CalType {
-        GREGORIAN("gregorian"),
-        ISO8601("iso8601"),
-
-        BUDDHIST("buddhist"),
-        CHINESE("chinese"),
-        COPTIC("coptic"),
-        DANGI("dangi"),
-        ETHIOPIC("ethiopic"),
-        ETHIOPIC_AMETE_ALEM("ethiopic-amete-alem"),
-        HEBREW("hebrew"),
-        INDIAN("indian"),
-        ISLAMIC("islamic"),
-        ISLAMIC_CIVIL("islamic-civil"),
-        ISLAMIC_RGSA("islamic-rgsa"),
-        ISLAMIC_TBLA("islamic-tbla"),
-        ISLAMIC_UMALQURA("islamic-umalqura"),
-        JAPANESE("japanese"),
-        PERSIAN("persian"),
-        ROC("roc"),
-
-        UNKNOWN("unknown");
-
-        String id;
-
-        CalType(String id) {
-            this.id = id;
-        }
-    }
-
     private static CalType getCalendarTypeForLocale(ULocale l) {
         String s = CalendarUtil.getCalendarType(l);
         if (s != null) {
             s = s.toLowerCase(Locale.ENGLISH);
             for (CalType type : CalType.values()) {
-                if (s.equals(type.id)) {
+                if (s.equals(type.getId())) {
                     return type;
                 }
             }
@@ -1965,8 +1936,8 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
         }
         // then, add other available clanedars
         for (CalType t : CalType.values()) {
-            if (!values.contains(t.id)) {
-                values.add(t.id);
+            if (!values.contains(t.getId())) {
+                values.add(t.getId());
             }
         }
         return values.toArray(new String[values.size()]);
@@ -2191,7 +2162,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
         CalType type = CalType.GREGORIAN;
         String typeString = getType();
         for (CalType testType : CalType.values()) {
-            if (typeString.equals(testType.id)) {
+            if (typeString.equals(testType.getId())) {
                 type = testType;
                 break;
             }
@@ -2265,7 +2236,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
         CalType type = CalType.GREGORIAN;
         String typeString = getType();
         for (CalType testType : CalType.values()) {
-            if (typeString.equals(testType.id)) {
+            if (typeString.equals(testType.getId())) {
                 type = testType;
                 break;
             }


=====================================
main/classes/core/src/com/ibm/icu/util/JapaneseCalendar.java
=====================================
@@ -10,6 +10,9 @@ package com.ibm.icu.util;
 import java.util.Date;
 import java.util.Locale;
 
+import com.ibm.icu.impl.CalType;
+import com.ibm.icu.impl.EraRules;
+
 /**
  * <code>JapaneseCalendar</code> is a subclass of <code>GregorianCalendar</code>
  * that numbers years and eras based on the reigns of the Japanese emperors.
@@ -24,19 +27,34 @@ import java.util.Locale;
  * of that year were in the Showa era, e.g. "January 6, 64 Showa", while the rest
  * of the year was in the Heisei era, e.g. "January 7, 1 Heisei".  This class
  * handles this distinction correctly when computing dates.  However, in lenient
- * mode either form of date is acceptable as input. 
+ * mode either form of date is acceptable as input.
  * <p>
  * In modern times, eras have started on January 8, 1868 AD, Gregorian (Meiji),
  * July 30, 1912 (Taisho), December 25, 1926 (Showa), and January 7, 1989 (Heisei).  Constants
  * for these eras, suitable for use in the <code>ERA</code> field, are provided
  * in this class.  Note that the <em>number</em> used for each era is more or
- * less arbitrary.  Currently, the era starting in 1053 AD is era #0; however this
- * may change in the future as we add more historical data.  Use the predefined
- * constants rather than using actual, absolute numbers.
+ * less arbitrary.  Currently, the era starting in 645 AD is era #0; however this
+ * may change in the future.  Use the predefined constants rather than using actual,
+ * absolute numbers.
+ * <p>
+ * Since ICU4J 63, start date of each era is imported from CLDR. CLDR era data
+ * may contain tentative era in near future with placeholder names. By default,
+ * such era data is not enabled. ICU4J users who want to test the behavior of
+ * the future era can enable this by one of following settings (in the priority
+ * order):
+ * <ol>
+ * <li>Java system property <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * <li>Environment variable <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * <li>Java system property <code>jdk.calendar.japanese.supplemental.era=xxx</code>.
+ *     (Note: This configuration is used for specifying a new era's start date and
+ *     names in OpenJDK. ICU4J implementation enables the CLDR tentative era when
+ *     this property is defined, but it does not use the start date and names specified
+ *     by the property value.)</li>
+ * </nl>
  * <p>
  * This class should not be subclassed.</p>
  * <p>
- * JapaneseCalendar usually should be instantiated using 
+ * JapaneseCalendar usually should be instantiated using
  * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
  * with the tag <code>"@calendar=japanese"</code>.</p>
  *
@@ -210,9 +228,44 @@ public class JapaneseCalendar extends GregorianCalendar {
     // Use 1970 as the default value of EXTENDED_YEAR
     private static final int GREGORIAN_EPOCH = 1970;
 
+    private static final EraRules ERA_RULES;
+
+    static {
+        // Although start date of next Japanese era is planned ahead, a name of
+        // new era might not be available. This implementation allows tester to
+        // check a new era without era names by settings below (in priority order).
+        // By default, such tentative era is disabled.
+        //
+        // 1. System property ICU_ENABLE_TENTATIVE_ERA=true or false
+        // 2. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false
+        // 3. Java system property - jdk.calendar.japanese.supplemental.era for Japanese
+        //
+        // Note: Java system property specifies the start date of new Japanese era,
+        //      but this implementation always uses the date read from ICU data.
+
+        boolean includeTentativeEra = false;
+
+        final String VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA";
+
+        String eraConf = System.getProperty(VAR_NAME);
+        if (eraConf == null) {
+            eraConf = System.getenv(VAR_NAME);
+        }
+
+        if (eraConf != null) {
+            includeTentativeEra = eraConf.equalsIgnoreCase("true");
+        } else {
+            String jdkEraConf = System.getProperty("jdk.calendar.japanese.supplemental.era");
+            includeTentativeEra = jdkEraConf != null;
+        }
+
+        ERA_RULES = EraRules.getInstance(CalType.JAPANESE, includeTentativeEra);
+    }
+
     /**
      * @stable ICU 2.8
      */
+    @Override
     protected int handleGetExtendedYear() {
         // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year
         // The default value of EXTENDED_YEAR is 1970 (Showa 45)
@@ -221,14 +274,14 @@ public class JapaneseCalendar extends GregorianCalendar {
             newerField(EXTENDED_YEAR, ERA) == EXTENDED_YEAR) {
             year = internalGet(EXTENDED_YEAR, GREGORIAN_EPOCH);
         } else {
-            // extended year is a gregorian year, where 1 = 1AD,  0 = 1BC, -1 = 2BC, etc 
-            year = internalGet(YEAR, 1)                       // pin to minimum of year 1 (first year)
-                    + ERAS[internalGet(ERA, CURRENT_ERA) * 3] // add gregorian starting year
-                    - 1;                                      // Subtract one because year starts at 1
+            // extended year is a gregorian year, where 1 = 1AD,  0 = 1BC, -1 = 2BC, etc
+            year = internalGet(YEAR, 1)                                     // pin to minimum of year 1 (first year)
+                    + ERA_RULES.getStartYear(internalGet(ERA, CURRENT_ERA)) // add gregorian starting year
+                    - 1;                                                    // Subtract one because year starts at 1
         }
         return year;
     }
-    
+
     /**
      * Called by handleComputeJulianDay.  Returns the default month (0-based) for the year,
      * taking year and era into account.  Defaults to 0 (JANUARY) for Gregorian.
@@ -238,18 +291,19 @@ public class JapaneseCalendar extends GregorianCalendar {
      * @draft ICU 3.6 (retain)
      * @see #MONTH
      */
-    protected int getDefaultMonthInYear(int extendedYear)
-    {
-      int era = internalGet(ERA, CURRENT_ERA);
-      //computeFields(status); // No need to compute fields here - expect the caller already did so.
-
-      // Find out if we are at the edge of an era
-      if(extendedYear == ERAS[era*3]) {
-        return ERAS[(era*3)+1] // month..
-            -1; // return 0-based month
-      } else {
-        return super.getDefaultMonthInYear(extendedYear);
-      }
+    @Override
+    protected int getDefaultMonthInYear(int extendedYear) {
+        int era = internalGet(ERA, CURRENT_ERA);
+        // computeFields(status); // No need to compute fields here - expect the caller already did so.
+
+        // Find out if we are at the edge of an era
+        int[] eraStart = ERA_RULES.getStartDate(era, null);
+        if (extendedYear == eraStart[0]) {
+            return eraStart[1]          // month..
+                    - 1;                // return 0-based month
+        } else {
+            return super.getDefaultMonthInYear(extendedYear);
+        }
     }
 
     /**
@@ -262,308 +316,33 @@ public class JapaneseCalendar extends GregorianCalendar {
      * @provisional ICU 3.6
      * @see #DAY_OF_MONTH
      */
+    @Override
     protected int getDefaultDayInMonth(int extendedYear, int month) {
-      int era = internalGet(ERA, CURRENT_ERA);
-          
-      if(extendedYear == ERAS[era*3]) { // if it is year 1..
-        if(month == ((ERAS[(era*3)+1])-1)) { // if it is the emperor's first month.. 
-          return ERAS[(era*3)+2]; // return the D_O_M of acession
+        int era = internalGet(ERA, CURRENT_ERA);
+        int[] eraStart = ERA_RULES.getStartDate(era, null);
+
+        if (extendedYear == eraStart[0]) {      // if it is year 1..
+            if (month == (eraStart[1] - 1)) {   // if it is the emperor's first month..
+                return eraStart[2];             // return the D_O_M of accession
+            }
         }
-      }
 
-      return super.getDefaultDayInMonth(extendedYear, month);
+        return super.getDefaultDayInMonth(extendedYear, month);
     }
 
     /**
      * @stable ICU 2.8
      */
+    @Override
     protected void handleComputeFields(int julianDay) {
         super.handleComputeFields(julianDay);
         int year = internalGet(EXTENDED_YEAR);
+        int eraIdx = ERA_RULES.getEraIndex(year, internalGet(MONTH) + 1 /* 1-base */, internalGet(DAY_OF_MONTH));
 
-        int low = 0;
-
-        // Short circuit for recent years.  Most modern computations will
-        // occur in the current era and won't require the binary search.
-        // Note that if the year is == the current era year, then we use
-        // the binary search to handle the month/dom comparison.
-        if (year > ERAS[ERAS.length - 3]) {
-            low = CURRENT_ERA;
-        } else {
-            // Binary search
-            int high = ERAS.length / 3;
-        
-            while (low < high - 1) {
-                int i = (low + high) / 2;
-                int diff = year - ERAS[i*3];
-
-                // If years are the same, then compare the months, and if those
-                // are the same, compare days of month.  In the ERAS array
-                // months are 1-based for easier maintenance.
-                if (diff == 0) {
-                    diff = internalGet(MONTH) - (ERAS[i*3 + 1] - 1);
-                    if (diff == 0) {
-                        diff = internalGet(DAY_OF_MONTH) - ERAS[i*3 + 2];
-                    }
-                }
-                if (diff >= 0) {
-                    low = i;
-                } else {
-                    high = i;
-                }
-            }
-        }
-
-        // Now we've found the last era that starts before this date, so
-        // adjust the year to count from the start of that era.  Note that
-        // all dates before the first era will fall into the first era by
-        // the algorithm.
-        internalSet(ERA, low);
-        internalSet(YEAR, year - ERAS[low*3] + 1);
+        internalSet(ERA, eraIdx);
+        internalSet(YEAR, year - ERA_RULES.getStartYear(eraIdx) + 1);
     }
 
-    private static final int[] ERAS = {
-    //  Gregorian date of each emperor's ascension
-    //  Years are AD, months are 1-based.
-    //  Year  Month Day
-         645,    6, 19,     // Taika
-         650,    2, 15,     // Hakuchi
-         672,    1,  1,     // Hakuho
-         686,    7, 20,     // Shucho
-         701,    3, 21,     // Taiho
-         704,    5, 10,     // Keiun
-         708,    1, 11,     // Wado
-         715,    9,  2,     // Reiki
-         717,   11, 17,     // Yoro
-         724,    2,  4,     // Jinki
-         729,    8,  5,     // Tempyo
-         749,    4, 14,     // Tempyo-kampo
-         749,    7,  2,     // Tempyo-shoho
-         757,    8, 18,     // Tempyo-hoji
-         765,    1,  7,     // Tempho-jingo
-         767,    8, 16,     // Jingo-keiun
-         770,   10,  1,     // Hoki
-         781,    1,  1,     // Ten-o
-         782,    8, 19,     // Enryaku
-         806,    5, 18,     // Daido
-         810,    9, 19,     // Konin
-         824,    1,  5,     // Tencho
-         834,    1,  3,     // Showa
-         848,    6, 13,     // Kajo
-         851,    4, 28,     // Ninju
-         854,   11, 30,     // Saiko
-         857,    2, 21,     // Tennan
-         859,    4, 15,     // Jogan
-         877,    4, 16,     // Genkei
-         885,    2, 21,     // Ninna
-         889,    4, 27,     // Kampyo
-         898,    4, 26,     // Shotai
-         901,    7, 15,     // Engi
-         923,    4, 11,     // Encho
-         931,    4, 26,     // Shohei
-         938,    5, 22,     // Tengyo
-         947,    4, 22,     // Tenryaku
-         957,   10, 27,     // Tentoku
-         961,    2, 16,     // Owa
-         964,    7, 10,     // Koho
-         968,    8, 13,     // Anna
-         970,    3, 25,     // Tenroku
-         973,   12, 20,     // Ten-en
-         976,    7, 13,     // Jogen
-         978,   11, 29,     // Tengen
-         983,    4, 15,     // Eikan
-         985,    4, 27,     // Kanna
-         987,    4,  5,     // Ei-en
-         989,    8,  8,     // Eiso
-         990,   11,  7,     // Shoryaku
-         995,    2, 22,     // Chotoku
-         999,    1, 13,     // Choho
-        1004,    7, 20,     // Kanko
-        1012,   12, 25,     // Chowa
-        1017,    4, 23,     // Kannin
-        1021,    2,  2,     // Jian
-        1024,    7, 13,     // Manju
-        1028,    7, 25,     // Chogen
-        1037,    4, 21,     // Choryaku
-        1040,   11, 10,     // Chokyu
-        1044,   11, 24,     // Kantoku
-        1046,    4, 14,     // Eisho
-        1053,    1, 11,     // Tengi
-        1058,    8, 29,     // Kohei
-        1065,    8,  2,     // Jiryaku
-        1069,    4, 13,     // Enkyu
-        1074,    8, 23,     // Shoho
-        1077,   11, 17,     // Shoryaku
-        1081,    2, 10,     // Eiho
-        1084,    2,  7,     // Otoku
-        1087,    4,  7,     // Kanji
-        1094,   12, 15,     // Kaho
-        1096,   12, 17,     // Eicho
-        1097,   11, 21,     // Shotoku
-        1099,    8, 28,     // Kowa
-        1104,    2, 10,     // Choji
-        1106,    4,  9,     // Kasho
-        1108,    8,  3,     // Tennin
-        1110,    7, 13,     // Ten-ei
-        1113,    7, 13,     // Eikyu
-        1118,    4,  3,     // Gen-ei
-        1120,    4, 10,     // Hoan
-        1124,    4,  3,     // Tenji
-        1126,    1, 22,     // Daiji
-        1131,    1, 29,     // Tensho
-        1132,    8, 11,     // Chosho
-        1135,    4, 27,     // Hoen
-        1141,    7, 10,     // Eiji
-        1142,    4, 28,     // Koji
-        1144,    2, 23,     // Tenyo
-        1145,    7, 22,     // Kyuan
-        1151,    1, 26,     // Ninpei
-        1154,   10, 28,     // Kyuju
-        1156,    4, 27,     // Hogen
-        1159,    4, 20,     // Heiji
-        1160,    1, 10,     // Eiryaku
-        1161,    9,  4,     // Oho
-        1163,    3, 29,     // Chokan
-        1165,    6,  5,     // Eiman
-        1166,    8, 27,     // Nin-an
-        1169,    4,  8,     // Kao
-        1171,    4, 21,     // Shoan
-        1175,    7, 28,     // Angen
-        1177,    8,  4,     // Jisho
-        1181,    7, 14,     // Yowa
-        1182,    5, 27,     // Juei
-        1184,    4, 16,     // Genryuku
-        1185,    8, 14,     // Bunji
-        1190,    4, 11,     // Kenkyu
-        1199,    4, 27,     // Shoji
-        1201,    2, 13,     // Kennin
-        1204,    2, 20,     // Genkyu
-        1206,    4, 27,     // Ken-ei
-        1207,   10, 25,     // Shogen
-        1211,    3,  9,     // Kenryaku
-        1213,   12,  6,     // Kenpo
-        1219,    4, 12,     // Shokyu
-        1222,    4, 13,     // Joo
-        1224,   11, 20,     // Gennin
-        1225,    4, 20,     // Karoku
-        1227,   12, 10,     // Antei
-        1229,    3,  5,     // Kanki
-        1232,    4,  2,     // Joei
-        1233,    4, 15,     // Tempuku
-        1234,   11,  5,     // Bunryaku
-        1235,    9, 19,     // Katei
-        1238,   11, 23,     // Ryakunin
-        1239,    2,  7,     // En-o
-        1240,    7, 16,     // Ninji
-        1243,    2, 26,     // Kangen
-        1247,    2, 28,     // Hoji
-        1249,    3, 18,     // Kencho
-        1256,   10,  5,     // Kogen
-        1257,    3, 14,     // Shoka
-        1259,    3, 26,     // Shogen
-        1260,    4, 13,     // Bun-o
-        1261,    2, 20,     // Kocho
-        1264,    2, 28,     // Bun-ei
-        1275,    4, 25,     // Kenji
-        1278,    2, 29,     // Koan
-        1288,    4, 28,     // Shoo
-        1293,    8, 55,     // Einin
-        1299,    4, 25,     // Shoan
-        1302,   11, 21,     // Kengen
-        1303,    8,  5,     // Kagen
-        1306,   12, 14,     // Tokuji
-        1308,   10,  9,     // Enkei
-        1311,    4, 28,     // Ocho
-        1312,    3, 20,     // Showa
-        1317,    2,  3,     // Bunpo
-        1319,    4, 28,     // Geno
-        1321,    2, 23,     // Genkyo
-        1324,   12,  9,     // Shochu
-        1326,    4, 26,     // Kareki
-        1329,    8, 29,     // Gentoku
-        1331,    8,  9,     // Genko
-        1334,    1, 29,     // Kemmu
-        1336,    2, 29,     // Engen
-        1340,    4, 28,     // Kokoku
-        1346,   12,  8,     // Shohei
-        1370,    7, 24,     // Kentoku
-        1372,    4,  1,     // Bunch\u0169
-        1375,    5, 27,     // Tenju
-        1379,    3, 22,     // Koryaku
-        1381,    2, 10,     // Kowa
-        1384,    4, 28,     // Gench\u0169
-        1384,    2, 27,     // Meitoku
-        1387,    8, 23,     // Kakei
-        1389,    2,  9,     // Koo
-        1390,    3, 26,     // Meitoku
-        1394,    7,  5,     // Oei
-        1428,    4, 27,     // Shocho
-        1429,    9,  5,     // Eikyo
-        1441,    2, 17,     // Kakitsu
-        1444,    2,  5,     // Bun-an
-        1449,    7, 28,     // Hotoku
-        1452,    7, 25,     // Kyotoku
-        1455,    7, 25,     // Kosho
-        1457,    9, 28,     // Choroku
-        1460,   12, 21,     // Kansho
-        1466,    2, 28,     // Bunsho
-        1467,    3,  3,     // Onin
-        1469,    4, 28,     // Bunmei
-        1487,    7, 29,     // Chokyo
-        1489,    8, 21,     // Entoku
-        1492,    7, 19,     // Meio
-        1501,    2, 29,     // Bunki
-        1504,    2, 30,     // Eisho
-        1521,    8, 23,     // Taiei
-        1528,    8, 20,     // Kyoroku
-        1532,    7, 29,     // Tenmon
-        1555,   10, 23,     // Koji
-        1558,    2, 28,     // Eiroku
-        1570,    4, 23,     // Genki
-        1573,    7, 28,     // Tensho
-        1592,   12,  8,     // Bunroku
-        1596,   10, 27,     // Keicho
-        1615,    7, 13,     // Genwa
-        1624,    2, 30,     // Kan-ei
-        1644,   12, 16,     // Shoho
-        1648,    2, 15,     // Keian
-        1652,    9, 18,     // Shoo
-        1655,    4, 13,     // Meiryaku
-        1658,    7, 23,     // Manji
-        1661,    4, 25,     // Kanbun
-        1673,    9, 21,     // Enpo
-        1681,    9, 29,     // Tenwa
-        1684,    2, 21,     // Jokyo
-        1688,    9, 30,     // Genroku
-        1704,    3, 13,     // Hoei
-        1711,    4, 25,     // Shotoku
-        1716,    6, 22,     // Kyoho
-        1736,    4, 28,     // Genbun
-        1741,    2, 27,     // Kanpo
-        1744,    2, 21,     // Enkyo
-        1748,    7, 12,     // Kan-en
-        1751,   10, 27,     // Horyaku
-        1764,    6,  2,     // Meiwa
-        1772,   11, 16,     // An-ei
-        1781,    4,  2,     // Tenmei
-        1789,    1, 25,     // Kansei
-        1801,    2,  5,     // Kyowa
-        1804,    2, 11,     // Bunka
-        1818,    4, 22,     // Bunsei
-        1830,   12, 10,     // Tenpo
-        1844,   12,  2,     // Koka
-        1848,    2, 28,     // Kaei
-        1854,   11, 27,     // Ansei
-        1860,    3, 18,     // Man-en
-        1861,    2, 19,     // Bunkyu
-        1864,    2, 20,     // Genji
-        1865,    4,  7,     // Keio
-        1868,    9,  8,     // Meiji
-        1912,    7, 30,     // Taisho
-        1926,   12, 25,     // Showa
-        1989,    1,  8,     // Heisei
-    };
-
     //-------------------------------------------------------------------------
     // Public constants for some of the recent eras that folks might use...
     //-------------------------------------------------------------------------
@@ -572,31 +351,31 @@ public class JapaneseCalendar extends GregorianCalendar {
     /**
      * @stable ICU 2.8
      */
-    static public final int CURRENT_ERA = (ERAS.length / 3) - 1;
-    
-    /** 
+    static public final int CURRENT_ERA = ERA_RULES.getCurrentEraIndex();
+
+    /**
      * Constant for the era starting on Sept. 8, 1868 AD.
-     * @stable  ICU 2.8 
+     * @stable  ICU 2.8
      */
-    static public final int MEIJI = CURRENT_ERA - 3;
+    static public final int MEIJI = 232;
 
-    /** 
-     * Constant for the era starting on July 30, 1912 AD. 
-     * @stable ICU 2.8 
+    /**
+     * Constant for the era starting on July 30, 1912 AD.
+     * @stable ICU 2.8
      */
-    static public final int TAISHO = CURRENT_ERA - 2;
-    
-    /** 
-     * Constant for the era starting on Dec. 25, 1926 AD. 
-     * @stable ICU 2.8 
+    static public final int TAISHO = 233;
+
+    /**
+     * Constant for the era starting on Dec. 25, 1926 AD.
+     * @stable ICU 2.8
      */
-    static public final int SHOWA = CURRENT_ERA - 1;
+    static public final int SHOWA = 234;
 
-    /** 
-     * Constant for the era starting on Jan. 7, 1989 AD. 
-     * @stable ICU 2.8 
+    /**
+     * Constant for the era starting on Jan. 7, 1989 AD.
+     * @stable ICU 2.8
      */
-    static public final int HEISEI = CURRENT_ERA;
+    static public final int HEISEI = 235;
 
     /**
      * Override GregorianCalendar.  We should really handle YEAR_WOY and
@@ -604,6 +383,7 @@ public class JapaneseCalendar extends GregorianCalendar {
      * not critical.
      * @stable ICU 2.8
      */
+    @Override
     @SuppressWarnings("fallthrough")
     protected int handleGetLimit(int field, int limitType) {
         switch (field) {
@@ -621,7 +401,7 @@ public class JapaneseCalendar extends GregorianCalendar {
             case LEAST_MAXIMUM:
                 return 1;
             case MAXIMUM:
-                return super.handleGetLimit(field, MAXIMUM) - ERAS[CURRENT_ERA*3];
+                return super.handleGetLimit(field, MAXIMUM) - ERA_RULES.getStartYear(CURRENT_ERA);
             }
             //Fall through to the default if not handled above
         }
@@ -634,6 +414,7 @@ public class JapaneseCalendar extends GregorianCalendar {
      * {@inheritDoc}
      * @stable ICU 3.8
      */
+    @Override
     public String getType() {
         return "japanese";
     }
@@ -643,6 +424,7 @@ public class JapaneseCalendar extends GregorianCalendar {
      * @internal
      * @deprecated This API is ICU internal only.
      */
+    @Override
     @Deprecated
     public boolean haveDefaultCentury() {
         return false;
@@ -652,6 +434,7 @@ public class JapaneseCalendar extends GregorianCalendar {
      * {@inheritDoc}
      * @stable ICU 4.0
      */
+    @Override
     public int getActualMaximum(int field) {
         if (field == YEAR) {
             int era = get(Calendar.ERA);
@@ -659,11 +442,12 @@ public class JapaneseCalendar extends GregorianCalendar {
                 // TODO: Investigate what value should be used here - revisit after 4.0.
                 return handleGetLimit(YEAR, MAXIMUM);
             } else {
-                int nextEraYear = ERAS[(era+1)*3];
-                int nextEraMonth = ERAS[(era+1)*3 + 1];
-                int nextEraDate = ERAS[(era+1)*3 + 2];
+                int[] nextEraStart = ERA_RULES.getStartDate(era + 1, null);
+                int nextEraYear = nextEraStart[0];
+                int nextEraMonth = nextEraStart[1]; // 1-base
+                int nextEraDate = nextEraStart[2];
 
-                int maxYear = nextEraYear - ERAS[era*3] + 1; // 1-base
+                int maxYear = nextEraYear - ERA_RULES.getStartYear(era) + 1; // 1-base
                 if (nextEraMonth == 1 && nextEraDate == 1) {
                     // Substract 1, because the next era starts at Jan 1
                     maxYear--;


=====================================
main/classes/core/src/com/ibm/icu/util/VersionInfo.java
=====================================
@@ -574,7 +574,7 @@ public final class VersionInfo implements Comparable<VersionInfo>
         UNICODE_10_0   = getInstance(10, 0, 0, 0);
         UNICODE_11_0   = getInstance(11, 0, 0, 0);
 
-        ICU_VERSION   = getInstance(62, 1, 0, 0);
+        ICU_VERSION   = getInstance(62, 2, 0, 0);
         ICU_DATA_VERSION = ICU_VERSION;
         UNICODE_VERSION = UNICODE_11_0;
 


=====================================
main/shared/build/common.properties
=====================================
@@ -7,7 +7,7 @@
 
 # Version numbers, etc.
 icu4j.spec.version = 62
-icu4j.impl.version = 62.1
+icu4j.impl.version = 62.2
 icu4j.data.version = 62
 default.exec.env = JavaSE-1.6
 


=====================================
main/shared/data/icudata.jar
=====================================
Binary files a/main/shared/data/icudata.jar and b/main/shared/data/icudata.jar differ


=====================================
main/shared/data/icutzdata.jar
=====================================
Binary files a/main/shared/data/icutzdata.jar and b/main/shared/data/icutzdata.jar differ


=====================================
main/shared/data/testdata.jar
=====================================
Binary files a/main/shared/data/testdata.jar and b/main/shared/data/testdata.jar differ


=====================================
main/tests/core/src/com/ibm/icu/dev/test/calendar/EraRulesTest.java
=====================================
@@ -0,0 +1,76 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.dev.test.calendar;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.impl.CalType;
+import com.ibm.icu.impl.EraRules;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.JapaneseCalendar;
+import com.ibm.icu.util.ULocale;
+
+/**
+ * Tests for EraRules class
+ */
+ at RunWith(JUnit4.class)
+public class EraRulesTest extends TestFmwk {
+    @Test
+    public void testAPIs() {
+        for (CalType calType : CalType.values()) {
+            String calId = calType.getId();
+            if (calId.equals("iso8601") || calId.equals("unknown")) {
+                continue;
+            }
+            EraRules rules1 = EraRules.getInstance(calType, false);
+            if (rules1 == null) {
+                errln("Era rules for " + calId + " is not available.");
+            }
+
+            EraRules rules2 = EraRules.getInstance(calType, true);
+            if (rules2 == null) {
+                errln("Era rules for " + calId + " (including tentative eras) is not available.");
+            }
+            int numEras1 = rules1.getNumberOfEras();
+            if (numEras1 <= 0) {
+                errln("Number of era rules for " + calId + " is " + numEras1);
+            }
+            int numEras2 = rules2.getNumberOfEras();
+            if (numEras2 < numEras1) {
+                errln("Number of era including tentative eras is fewer than one without tentative eras in calendar: "
+                        + calId);
+            }
+
+            Calendar cal = Calendar.getInstance(new ULocale("en"));
+            int currentIdx = rules1.getCurrentEraIndex();
+            int currentYear = cal.get(Calendar.YEAR);
+            int idx = rules1.getEraIndex(currentYear, cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE));
+            if (idx != currentIdx) {
+                errln("Current era index:" + currentIdx + " is different from era index of now:" + idx
+                        + " in calendar:" + calId);
+            }
+
+            int eraStartYear = rules1.getStartYear(currentIdx);
+            if (currentYear < eraStartYear) {
+                errln("Current era's start year is after the current year in calendar:" + calId);
+            }
+        }
+    }
+
+    @Test
+    public void testJapanese() {
+        EraRules rules = EraRules.getInstance(CalType.JAPANESE, true);
+        // Rules should have an era after Heisei
+        int numRules = rules.getNumberOfEras();
+        if (numRules <= JapaneseCalendar.HEISEI) {
+            errln("Era after Heisei is not available.");
+        }
+        int postHeiseiStartYear = rules.getStartYear(JapaneseCalendar.HEISEI + 1);
+        if (postHeiseiStartYear != 2019) {
+            errln("Era after Heisei should start in 2019, but got " + postHeiseiStartYear);
+        }
+    }
+}


=====================================
main/tests/core/src/com/ibm/icu/dev/test/calendar/JapaneseTest.java
=====================================
@@ -154,9 +154,9 @@ public class JapaneseTest extends CalendarTestFmwk {
         Calendar cal = new JapaneseCalendar(loc);
         DateFormat enjformat = cal.getDateTimeFormat(0,0,new ULocale("en_JP at calendar=japanese"));
         DateFormat format = cal.getDateTimeFormat(0,0,loc);
-        ((SimpleDateFormat)format).applyPattern("y.M.d");  // Note: just 'y' doesn't work here.
+        ((SimpleDateFormat)format).applyPattern("y/M/d");  // Note: just 'y' doesn't work here.
         ParsePosition pos = new ParsePosition(0);
-        Date aDate = format.parse("1.1.9", pos); // after the start of heisei accession.  Jan 1, 1H wouldn't work  because it is actually showa 64
+        Date aDate = format.parse("1/5/9", pos); // after the start of Reiwa accession.  Jan 1, R1 wouldn't work  because it is actually Heisei 31
         String inEn = enjformat.format(aDate);
 
         cal.clear();
@@ -165,7 +165,7 @@ public class JapaneseTest extends CalendarTestFmwk {
         int gotEra = cal.get(Calendar.ERA);
 
         int expectYear = 1;
-        int expectEra = JapaneseCalendar.CURRENT_ERA;
+        int expectEra = JapaneseCalendar.CURRENT_ERA; // Reiwa
 
         if((gotYear != expectYear) || (gotEra != expectEra)) {
             errln("Expected year " + expectYear + ", era " + expectEra +", but got year " + gotYear + " and era " + gotEra + ", == " + inEn);
@@ -173,7 +173,7 @@ public class JapaneseTest extends CalendarTestFmwk {
             logln("Got year " + gotYear + " and era " + gotEra + ", == " + inEn);
         }
 
-        // Test parse with missing era (should default to current era, heisei)
+        // Test parse with missing era (should default to current era)
         // Test parse with incomplete information
         logln("Testing parse w/ just year...");
         Calendar cal2 = new JapaneseCalendar(loc);
@@ -197,7 +197,7 @@ public class JapaneseTest extends CalendarTestFmwk {
         gotYear = cal2.get(Calendar.YEAR);
         gotEra = cal2.get(Calendar.ERA);
         expectYear = 1;
-        expectEra = JapaneseCalendar.CURRENT_ERA;
+        expectEra = JapaneseCalendar.CURRENT_ERA;  // Reiwa
         if((gotYear != 1) || (gotEra != expectEra)) {
             errln("parse "+ samplestr + " of 'y' as Japanese Calendar, expected year " + expectYear +
                 " and era " + expectEra + ", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
@@ -379,5 +379,29 @@ public class JapaneseTest extends CalendarTestFmwk {
         doLimitsTest(jcal, null, cal.getTime());
         doTheoreticalLimitsTest(jcal, true);
     }
-}
 
+    public void TestHeiseiToReiwa() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(2019, Calendar.APRIL, 29);
+
+        DateFormat jfmt = DateFormat.getDateInstance(DateFormat.LONG, new ULocale("ja at calendar=japanese"));
+
+        final String[] EXPECTED_FORMAT = {
+                "\u5E73\u621031\u5E744\u670829\u65E5",  // Heisei 31 April 29
+                "\u5E73\u621031\u5E744\u670830\u65E5",  // Heisei 31 April 30
+                "\u4EE4\u548C1\u5E745\u67081\u65E5",    // Reiwa 1 May 1
+                "\u4EE4\u548C1\u5E745\u67082\u65E5",    // Reiwa 1 May 2
+        };
+
+        for (int i = 0; i < EXPECTED_FORMAT.length; i++) {
+            Date d = cal.getTime();
+            String dateStr = jfmt.format(d);
+            if (!EXPECTED_FORMAT[i].equals(dateStr)) {
+                errln("Formatting year:" + cal.get(Calendar.YEAR) + " month:" + (cal.get(Calendar.MONTH) + 1)
+                        + " day:" + cal.get(Calendar.DATE) + " - expected: " + EXPECTED_FORMAT[i]
+                        + " / actual: " + dateStr);
+            }
+            cal.add(Calendar.DATE, 1);
+        }
+    }
+}


=====================================
main/tests/core/src/com/ibm/icu/dev/test/lang/UCharacterCaseTest.java
=====================================
@@ -1493,6 +1493,16 @@ public final class UCharacterCaseTest extends TestFmwk
         }
     }
 
+    @Test
+    public void TestCaseMapGreekExtended() {
+        // Ticket 13851
+        String s = "\u1F80\u1F88\u1FFC";
+        String result = CaseMap.toLower().apply(Locale.ROOT,  s);
+        assertEquals("lower", "\u1F80\u1F80\u1FF3", result);
+        result = CaseMap.toTitle().apply(Locale.ROOT, null, s);
+        assertEquals("title", "\u1F88\u1F80\u1FF3", result);
+    }
+
     // private data members - test data --------------------------------------
 
     private static final Locale TURKISH_LOCALE_ = new Locale("tr", "TR");


=====================================
main/tests/core/src/com/ibm/icu/dev/test/util/DebugUtilitiesData.java
=====================================
@@ -10,7 +10,7 @@
 package com.ibm.icu.dev.test.util;
 
 public class DebugUtilitiesData extends Object {
-    public static final String ICU4C_VERSION="62.1";
+    public static final String ICU4C_VERSION="62.2";
     public static final int UDebugEnumType = 0;
     public static final int UCalendarDateFields = 1;
     public static final int UCalendarMonths = 2;


=====================================
maven/icu4j-charset/pom.xml
=====================================
@@ -17,17 +17,18 @@
   </description>
   <url>http://icu-project.org/</url>
   <inceptionYear>2001</inceptionYear>
+
   <licenses>
     <license>
       <name>Unicode/ICU License</name>
-      <url>http://source.icu-project.org/repos/icu/trunk/icu4j/main/shared/licenses/LICENSE</url>
+      <url>https://raw.githubusercontent.com/unicode-org/icu/master/icu4c/LICENSE</url>
       <distribution>repo</distribution>
     </license>
   </licenses>
 
   <developers>
     <developer>
-      <id>mark</id>
+      <id>macchiati</id>
       <name>Mark Davis</name>
       <organization>Google</organization>
       <roles>
@@ -35,7 +36,7 @@
       </roles>
     </developer>
     <developer>
-      <id>emmons</id>
+      <id>JCEmmons</id>
       <name>John Emmons</name>
       <organization>IBM Corporation</organization>
       <roles>
@@ -43,7 +44,7 @@
       </roles>
     </developer>
     <developer>
-      <id>doug</id>
+      <id>dougfelt</id>
       <name>Doug Felt</name>
       <organization>Google</organization>
       <roles>
@@ -59,7 +60,7 @@
       </roles>
     </developer>
     <developer>
-      <id>srl</id>
+      <id>srl295</id>
       <name>Steven Loomis</name>
       <organization>IBM Corporation</organization>
       <roles>
@@ -67,7 +68,7 @@
       </roles>
     </developer>
     <developer>
-      <id>markus</id>
+      <id>markusicu</id>
       <name>Markus Scherer</name>
       <organization>Google</organization>
       <roles>
@@ -83,7 +84,7 @@
       </roles>
     </developer>
     <developer>
-      <id>yoshito</id>
+      <id>yumaoka</id>
       <name>Yoshito Umaoka</name>
       <organization>IBM Corporation</organization>
       <roles>
@@ -117,13 +118,14 @@
   </mailingLists>
 
   <scm>
-    <connection>scm:svn:http://source.icu-project.org/repos/icu/trunk/icu4j</connection>
-    <developerConnection>scm:svn:http://source.icu-project.org/repos/icu/trunk/icu4j</developerConnection>
-    <url>http://source.icu-project.org/repos/icu/trunk/icu4j</url>
+    <connection>scm:git:git://github.com/unicode-org/icu.git</connection>
+    <developerConnection>scm:git:git at github.com:unicode-org/icu.git</developerConnection>
+    <url>https://github.com/unicode-org/icu</url>
   </scm>
+
   <issueManagement>
-    <system>Trac</system>
-    <url>http://bugs.icu-project.org/trac/</url>
+    <system>JIRA</system>
+    <url>https://unicode-org.atlassian.net/projects/ICU</url>
   </issueManagement>
 
   <distributionManagement>
@@ -146,4 +148,4 @@
       <version>@POMVERSION@</version>
     </dependency>
   </dependencies>
-</project>
+</project>
\ No newline at end of file


=====================================
maven/icu4j-localespi/pom.xml
=====================================
@@ -17,17 +17,18 @@
   </description>
   <url>http://icu-project.org/</url>
   <inceptionYear>2001</inceptionYear>
+
   <licenses>
     <license>
       <name>Unicode/ICU License</name>
-      <url>http://source.icu-project.org/repos/icu/trunk/icu4j/main/shared/licenses/LICENSE</url>
+      <url>https://raw.githubusercontent.com/unicode-org/icu/master/icu4c/LICENSE</url>
       <distribution>repo</distribution>
     </license>
   </licenses>
 
   <developers>
     <developer>
-      <id>mark</id>
+      <id>macchiati</id>
       <name>Mark Davis</name>
       <organization>Google</organization>
       <roles>
@@ -35,7 +36,7 @@
       </roles>
     </developer>
     <developer>
-      <id>emmons</id>
+      <id>JCEmmons</id>
       <name>John Emmons</name>
       <organization>IBM Corporation</organization>
       <roles>
@@ -43,7 +44,7 @@
       </roles>
     </developer>
     <developer>
-      <id>doug</id>
+      <id>dougfelt</id>
       <name>Doug Felt</name>
       <organization>Google</organization>
       <roles>
@@ -59,7 +60,7 @@
       </roles>
     </developer>
     <developer>
-      <id>srl</id>
+      <id>srl295</id>
       <name>Steven Loomis</name>
       <organization>IBM Corporation</organization>
       <roles>
@@ -67,7 +68,7 @@
       </roles>
     </developer>
     <developer>
-      <id>markus</id>
+      <id>markusicu</id>
       <name>Markus Scherer</name>
       <organization>Google</organization>
       <roles>
@@ -83,7 +84,7 @@
       </roles>
     </developer>
     <developer>
-      <id>yoshito</id>
+      <id>yumaoka</id>
       <name>Yoshito Umaoka</name>
       <organization>IBM Corporation</organization>
       <roles>
@@ -117,13 +118,14 @@
   </mailingLists>
 
   <scm>
-    <connection>scm:svn:http://source.icu-project.org/repos/icu/trunk/icu4j</connection>
-    <developerConnection>scm:svn:http://source.icu-project.org/repos/icu/trunk/icu4j</developerConnection>
-    <url>http://source.icu-project.org/repos/icu/trunk/icu4j</url>
+    <connection>scm:git:git://github.com/unicode-org/icu.git</connection>
+    <developerConnection>scm:git:git at github.com:unicode-org/icu.git</developerConnection>
+    <url>https://github.com/unicode-org/icu</url>
   </scm>
+
   <issueManagement>
-    <system>Trac</system>
-    <url>http://bugs.icu-project.org/trac/</url>
+    <system>JIRA</system>
+    <url>https://unicode-org.atlassian.net/projects/ICU</url>
   </issueManagement>
 
   <distributionManagement>
@@ -146,4 +148,4 @@
       <version>@POMVERSION@</version>
     </dependency>
   </dependencies>
-</project>
+</project>
\ No newline at end of file


=====================================
maven/icu4j/pom.xml
=====================================
@@ -22,17 +22,18 @@
   </description>
   <url>http://icu-project.org/</url>
   <inceptionYear>2001</inceptionYear>
+
   <licenses>
     <license>
       <name>Unicode/ICU License</name>
-      <url>http://source.icu-project.org/repos/icu/trunk/icu4j/main/shared/licenses/LICENSE</url>
+      <url>https://raw.githubusercontent.com/unicode-org/icu/master/icu4c/LICENSE</url>
       <distribution>repo</distribution>
     </license>
   </licenses>
 
   <developers>
     <developer>
-      <id>mark</id>
+      <id>macchiati</id>
       <name>Mark Davis</name>
       <organization>Google</organization>
       <roles>
@@ -40,7 +41,7 @@
       </roles>
     </developer>
     <developer>
-      <id>emmons</id>
+      <id>JCEmmons</id>
       <name>John Emmons</name>
       <organization>IBM Corporation</organization>
       <roles>
@@ -48,7 +49,7 @@
       </roles>
     </developer>
     <developer>
-      <id>doug</id>
+      <id>dougfelt</id>
       <name>Doug Felt</name>
       <organization>Google</organization>
       <roles>
@@ -64,7 +65,7 @@
       </roles>
     </developer>
     <developer>
-      <id>srl</id>
+      <id>srl295</id>
       <name>Steven Loomis</name>
       <organization>IBM Corporation</organization>
       <roles>
@@ -72,7 +73,7 @@
       </roles>
     </developer>
     <developer>
-      <id>markus</id>
+      <id>markusicu</id>
       <name>Markus Scherer</name>
       <organization>Google</organization>
       <roles>
@@ -88,7 +89,7 @@
       </roles>
     </developer>
     <developer>
-      <id>yoshito</id>
+      <id>yumaoka</id>
       <name>Yoshito Umaoka</name>
       <organization>IBM Corporation</organization>
       <roles>
@@ -122,13 +123,14 @@
   </mailingLists>
 
   <scm>
-    <connection>scm:svn:http://source.icu-project.org/repos/icu/trunk/icu4j</connection>
-    <developerConnection>scm:svn:http://source.icu-project.org/repos/icu/trunk/icu4j</developerConnection>
-    <url>http://source.icu-project.org/repos/icu/trunk/icu4j</url>
+    <connection>scm:git:git://github.com/unicode-org/icu.git</connection>
+    <developerConnection>scm:git:git at github.com:unicode-org/icu.git</developerConnection>
+    <url>https://github.com/unicode-org/icu</url>
   </scm>
+
   <issueManagement>
-    <system>Trac</system>
-    <url>http://bugs.icu-project.org/trac/</url>
+    <system>JIRA</system>
+    <url>https://unicode-org.atlassian.net/projects/ICU</url>
   </issueManagement>
 
   <distributionManagement>
@@ -143,4 +145,4 @@
       <url>https://oss.sonatype.org/content/repositories/snapshots</url>
     </snapshotRepository>
   </distributionManagement>
-</project>
+</project>
\ No newline at end of file


=====================================
readme.html
=====================================
@@ -14,13 +14,15 @@ h3.doc { text-decoration: underline }
 <body style="background-color: rgb(255, 255, 255);" lang="EN-US"
  link="#0000ff" vlink="#800080">
 <h1>International Components for Unicode for Java (ICU4J)</h1>
-<h2>Read Me for ICU4J 62.1</h2>
-(Last Update: 2018-June-12)
+<h2>Read Me for ICU4J 62.2</h2>
+(Last Update: 2019-Apr-10)
 <hr size="2" width="100%">
 
 <p>
-<b>Note:</b> This is major release of ICU4J. It contains bug fixes and adds implementations
-of inherited API and introduces new API or functionality.
+<b>Note:</b> This is an update release of ICU4J 62. This release contains bug
+fixes and updated data, but does not introduce any new APIs for functionalities.
+<!-- <b>Note:</b> This is major release of ICU4J. It contains bug fixes and adds implementations
+of inherited API and introduces new API or functionality. -->
 <!-- <b>Note:</b> This is a development milestone of ICU4J 62.
 The contents of this document may not reflect the recent changes done
 for ICU 62 development. It is not recommended for production use. -->
@@ -180,19 +182,19 @@ builds, and they are packaged in jar files for convenient download.
 <dependency>
     <groupId>com.ibm.icu</groupId>
     <artifactId>icu4j</artifactId>
-    <version>62.1</version>
+    <version>62.2</version>
 </dependency>
 
 <dependency>
     <groupId>com.ibm.icu</groupId>
     <artifactId>icu4j-charset</artifactId>
-    <version>62.1</version>
+    <version>62.2</version>
 </dependency>
 
 <dependency>
     <groupId>com.ibm.icu</groupId>
     <artifactId>icu4j-localespi</artifactId>
-    <version>62.1</version>
+    <version>62.2</version>
 </dependency>
 </pre>
   </ul>
@@ -877,7 +879,7 @@ ICU4J data is built by ICU4C tools. Please see "icu4j-readme.txt" in icu4c/sourc
 <I> Note: This procedure assumes that all 3 sources are present</I>
 <ol>
     <li>Checkout or download CLDR version 'release-33'</li>
-    <li>Checkout ICU with tag 'release-62-1'</li>
+    <li>Checkout ICU with tag 'release-62-2'</li>
     <li>cd to icu4c/source/data directory</li>
     <li>Follow the instructions in icu4c/source/data/cldr-icu-readme.txt</li>
     <li>Rebuild ICU4C with the newly generated data.</li>



View it on GitLab: https://salsa.debian.org/java-team/icu4j/-/commit/7ac9cf3e6d818fb20591b61dbfcc5298b191c097

-- 
View it on GitLab: https://salsa.debian.org/java-team/icu4j/-/commit/7ac9cf3e6d818fb20591b61dbfcc5298b191c097
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20210105/ea2b55c8/attachment.html>


More information about the pkg-java-commits mailing list