diff options
16 files changed, 127 insertions, 14 deletions
diff --git a/android_icu4j/src/main/java/android/icu/number/NumberPropertyMapper.java b/android_icu4j/src/main/java/android/icu/number/NumberPropertyMapper.java index 1874a558f..81d635615 100644 --- a/android_icu4j/src/main/java/android/icu/number/NumberPropertyMapper.java +++ b/android_icu4j/src/main/java/android/icu/number/NumberPropertyMapper.java @@ -123,6 +123,21 @@ final class NumberPropertyMapper { MathContext mathContext = RoundingUtils.getMathContextOrUnlimited(properties); boolean explicitMinMaxFrac = minFrac != -1 || maxFrac != -1; boolean explicitMinMaxSig = minSig != -1 || maxSig != -1; + // Resolve min/max frac for currencies, required for the validation logic and for when minFrac or maxFrac was + // set (but not both) on a currency instance. + // NOTE: Increments are handled in "Rounder.constructCurrency()". + if (useCurrency) { + if (minFrac == -1 && maxFrac == -1) { + minFrac = currency.getDefaultFractionDigits(currencyUsage); + maxFrac = currency.getDefaultFractionDigits(currencyUsage); + } else if (minFrac == -1) { + minFrac = Math.min(maxFrac, currency.getDefaultFractionDigits(currencyUsage)); + } else if (maxFrac == -1) { + maxFrac = Math.max(minFrac, currency.getDefaultFractionDigits(currencyUsage)); + } else { + // No-op: user override for both minFrac and maxFrac + } + } // Validate min/max int/frac. // For backwards compatibility, minimum overrides maximum if the two conflict. // The following logic ensures that there is always a minimum of at least one digit. diff --git a/android_icu4j/src/main/java/android/icu/text/DictionaryBreakEngine.java b/android_icu4j/src/main/java/android/icu/text/DictionaryBreakEngine.java index 65d4737cb..9d7d2a5df 100644 --- a/android_icu4j/src/main/java/android/icu/text/DictionaryBreakEngine.java +++ b/android_icu4j/src/main/java/android/icu/text/DictionaryBreakEngine.java @@ -98,7 +98,7 @@ abstract class DictionaryBreakEngine implements LanguageBreakEngine { @Override public Object clone() throws CloneNotSupportedException { DequeI result = (DequeI)super.clone(); - data = data.clone(); + result.data = data.clone(); return result; } diff --git a/android_icu4j/src/main/java/android/icu/text/SimpleDateFormat.java b/android_icu4j/src/main/java/android/icu/text/SimpleDateFormat.java index c8bb6dd7d..1e5ee7b37 100644 --- a/android_icu4j/src/main/java/android/icu/text/SimpleDateFormat.java +++ b/android_icu4j/src/main/java/android/icu/text/SimpleDateFormat.java @@ -1903,7 +1903,7 @@ public class SimpleDateFormat extends DateFormat { // 12 am is 12 midnight, and 12 pm is 12 noon. value = cal.get(Calendar.AM_PM); - if (count == 3) { + if (count <= 3) { toAppend = formatData.abbreviatedDayPeriods[value]; } else if (count == 4 || count > 5) { toAppend = formatData.wideDayPeriods[value]; diff --git a/android_icu4j/src/main/java/android/icu/util/VersionInfo.java b/android_icu4j/src/main/java/android/icu/util/VersionInfo.java index 9698bf9c1..ba8922215 100644 --- a/android_icu4j/src/main/java/android/icu/util/VersionInfo.java +++ b/android_icu4j/src/main/java/android/icu/util/VersionInfo.java @@ -527,8 +527,8 @@ public final class VersionInfo implements Comparable<VersionInfo> UNICODE_9_0 = getInstance(9, 0, 0, 0); UNICODE_10_0 = getInstance(10, 0, 0, 0); - ICU_VERSION = getInstance(60, 1, 0, 0); - ICU_DATA_VERSION = getInstance(60, 1, 0, 0); + ICU_VERSION = getInstance(60, 2, 0, 0); + ICU_DATA_VERSION = getInstance(60, 2, 0, 0); UNICODE_VERSION = UNICODE_10_0; UCOL_RUNTIME_VERSION = getInstance(9); diff --git a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/ibm9027.cnv b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/ibm9027.cnv Binary files differindex 48f19ef2e..9502a7e86 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/ibm9027.cnv +++ b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/ibm9027.cnv diff --git a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test1.cnv b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test1.cnv Binary files differindex 344a17f7a..6575fbee2 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test1.cnv +++ b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test1.cnv diff --git a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test1bmp.cnv b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test1bmp.cnv Binary files differindex 48ce63c54..c8e37a967 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test1bmp.cnv +++ b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test1bmp.cnv diff --git a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test2.cnv b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test2.cnv Binary files differindex ef8fd3f0c..34d98550e 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test2.cnv +++ b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test2.cnv diff --git a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test3.cnv b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test3.cnv Binary files differindex f29586edf..81cdbb64a 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test3.cnv +++ b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test3.cnv diff --git a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test4.cnv b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test4.cnv Binary files differindex 274420a18..a8f37a982 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test4.cnv +++ b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test4.cnv diff --git a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test4x.cnv b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test4x.cnv Binary files differindex e1ef8d2e5..d17a078bf 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test4x.cnv +++ b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test4x.cnv diff --git a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test5.cnv b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test5.cnv Binary files differindex 669cbd2a7..25f94469d 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test5.cnv +++ b/android_icu4j/src/main/tests/android/icu/dev/data/testdata/test5.cnv diff --git a/android_icu4j/src/main/tests/android/icu/dev/test/format/DateFormatTest.java b/android_icu4j/src/main/tests/android/icu/dev/test/format/DateFormatTest.java index 440e9060b..3e67db93e 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/test/format/DateFormatTest.java +++ b/android_icu4j/src/main/tests/android/icu/dev/test/format/DateFormatTest.java @@ -4942,19 +4942,19 @@ public class DateFormatTest extends TestFmwk { long k180000 = 1447437600000L; // Short. - SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss bbb"); + SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss bbb", Locale.ENGLISH); sdf.setTimeZone(TimeZone.GMT_ZONE); // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day. // For ICU 57 output of "midnight" is temporarily suppressed. -// assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000)); - assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 AM", sdf.format(k000000)); - assertEquals("hh:mm:ss bbbb | 00:00:30", "12:00:30 AM", sdf.format(k000030)); - assertEquals("hh:mm:ss bbbb | 00:30:00", "12:30:00 AM", sdf.format(k003000)); - assertEquals("hh:mm:ss bbbb | 06:00:00", "06:00:00 AM", sdf.format(k060000)); - assertEquals("hh:mm:ss bbbb | 12:00:00", "12:00:00 noon", sdf.format(k120000)); - assertEquals("hh:mm:ss bbbb | 18:00:00", "06:00:00 PM", sdf.format(k180000)); +// assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000)); + assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 AM", sdf.format(k000000)); + assertEquals("hh:mm:ss bbb | 00:00:30", "12:00:30 AM", sdf.format(k000030)); + assertEquals("hh:mm:ss bbb | 00:30:00", "12:30:00 AM", sdf.format(k003000)); + assertEquals("hh:mm:ss bbb | 06:00:00", "06:00:00 AM", sdf.format(k060000)); + assertEquals("hh:mm:ss bbb | 12:00:00", "12:00:00 noon", sdf.format(k120000)); + assertEquals("hh:mm:ss bbb | 18:00:00", "06:00:00 PM", sdf.format(k180000)); sdf.applyPattern("hh:mm bbb"); @@ -4963,6 +4963,7 @@ public class DateFormatTest extends TestFmwk { // assertEquals("hh:mm bbb | 00:00:30", "12:00 midnight", sdf.format(k000030)); assertEquals("hh:mm bbb | 00:00:30", "12:00 AM", sdf.format(k000030)); assertEquals("hh:mm bbb | 00:30:00", "12:30 AM", sdf.format(k003000)); + assertEquals("hh:mm bbb | 12:00:00", "12:00 noon", sdf.format(k120000)); sdf.applyPattern("hh bbb"); @@ -4972,6 +4973,26 @@ public class DateFormatTest extends TestFmwk { assertEquals("hh bbb | 00:00:30", "12 AM", sdf.format(k000030)); // assertEquals("hh bbb | 00:30:00", "12 midnight", sdf.format(k003000)); assertEquals("hh bbb | 00:30:00", "12 AM", sdf.format(k003000)); + assertEquals("hh bbb | 12:00:00", "12 noon", sdf.format(k120000)); + + sdf.applyPattern("hh:mm b"); + +// assertEquals("hh:mm b | 00:00:00", "12:00 midnight", sdf.format(k000000)); + assertEquals("hh:mm b | 00:00:00", "12:00 AM", sdf.format(k000000)); +// assertEquals("hh:mm b | 00:00:30", "12:00 midnight", sdf.format(k000030)); + assertEquals("hh:mm b | 00:00:30", "12:00 AM", sdf.format(k000030)); + assertEquals("hh:mm b | 00:30:00", "12:30 AM", sdf.format(k003000)); + assertEquals("hh:mm b | 12:00:00", "12:00 noon", sdf.format(k120000)); + + sdf.applyPattern("hh b"); + +// assertEquals("hh b | 00:00:00", "12 midnight", sdf.format(k000000)); + assertEquals("hh b | 00:00:00", "12 AM", sdf.format(k000000)); +// assertEquals("hh b | 00:00:30", "12 midnight", sdf.format(k000030)); + assertEquals("hh b | 00:00:30", "12 AM", sdf.format(k000030)); +// assertEquals("hh b | 00:30:00", "12 midnight", sdf.format(k003000)); + assertEquals("hh b | 00:30:00", "12 AM", sdf.format(k003000)); + assertEquals("hh b | 12:00:00", "12 noon", sdf.format(k120000)); // Wide. sdf.applyPattern("hh:mm:ss bbbb"); diff --git a/android_icu4j/src/main/tests/android/icu/dev/test/format/NumberFormatTest.java b/android_icu4j/src/main/tests/android/icu/dev/test/format/NumberFormatTest.java index c6f1449e7..33cde0bc7 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/test/format/NumberFormatTest.java +++ b/android_icu4j/src/main/tests/android/icu/dev/test/format/NumberFormatTest.java @@ -5569,7 +5569,7 @@ public class NumberFormatTest extends TestFmwk { df.setMaximumFractionDigits(3); expect2(df, 35.0, "$35.000"); df.setMinimumFractionDigits(-1); - expect2(df, 35.0, "$35"); + expect2(df, 35.0, "$35.00"); df.setMaximumFractionDigits(-1); expect2(df, 35.0, "$35.00"); } @@ -5919,4 +5919,21 @@ public class NumberFormatTest extends TestFmwk { expect2(df, 100, "a100"); expect2(df, -100, "-a100"); } + + @Test + public void TestCurrencyRoundingMinWithoutMax() { + NumberFormat currencyFormat = DecimalFormat.getCurrencyInstance(Locale.US); + currencyFormat.setCurrency(Currency.getInstance("AUD")); + currencyFormat.setMinimumFractionDigits(0); + expect(currencyFormat, 0.001, "A$0"); + + // NOTE: The size of the increment takes precedent over minFrac since ICU 59. + // CAD-Cash uses nickel rounding. + currencyFormat = DecimalFormat.getCurrencyInstance(Locale.US); + currencyFormat.setCurrency(Currency.getInstance("CAD")); + ((DecimalFormat)currencyFormat).setCurrencyUsage(CurrencyUsage.CASH); + currencyFormat.setMinimumFractionDigits(0); + // expect(currencyFormat, 0.08, "CA$0.1"); // ICU 58 and down + expect(currencyFormat, 0.08, "CA$0.10"); // ICU 59 and up + } } diff --git a/android_icu4j/src/main/tests/android/icu/dev/test/rbbi/RBBITest.java b/android_icu4j/src/main/tests/android/icu/dev/test/rbbi/RBBITest.java index d714d8c26..bf5ee8d0a 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/test/rbbi/RBBITest.java +++ b/android_icu4j/src/main/tests/android/icu/dev/test/rbbi/RBBITest.java @@ -491,4 +491,64 @@ public class RBBITest extends TestFmwk { assertEquals("", biFr, cloneFr); assertEquals("", ULocale.FRENCH, cloneFr.getLocale(ULocale.VALID_LOCALE)); } + + static class T13512Thread extends Thread { + private String fText; + public List fBoundaries; + public List fExpectedBoundaries; + + T13512Thread(String text) { + fText = text; + fExpectedBoundaries = getBoundary(fText); + } + @Override + public void run() { + for (int i= 0; i<10000; ++i) { + fBoundaries = getBoundary(fText); + if (!fBoundaries.equals(fExpectedBoundaries)) { + break; + } + } + } + private static final BreakIterator BREAK_ITERATOR_CACHE = BreakIterator.getWordInstance(ULocale.ROOT); + public static List<Integer> getBoundary(String toParse) { + List<Integer> retVal = new ArrayList<Integer>(); + BreakIterator bi = (BreakIterator) BREAK_ITERATOR_CACHE.clone(); + bi.setText(toParse); + for (int boundary=bi.first(); boundary != BreakIterator.DONE; boundary = bi.next()) { + retVal.add(boundary); + } + return retVal; + } + } + + @Test + public void TestBug13512() { + String japanese = "コンピューターは、本質的には数字しか扱うことができません。コンピューターは、文字や記号などのそれぞれに番号を割り振る" + + "ことによって扱えるようにします。ユニコードが出来るまでは、これらの番号を割り振る仕組みが何百種類も存在しました。どの一つをとっても、十分な" + + "文字を含んではいませんでした。例えば、欧州連合一つを見ても、そのすべての言語をカバーするためには、いくつかの異なる符号化の仕" + + "組みが必要でした。英語のような一つの言語に限っても、一つだけの符号化の仕組みでは、一般的に使われるすべての文字、句読点、技術" + + "的な記号などを扱うには不十分でした。"; + + String thai = "โดยพื้นฐานแล้ว, คอมพิวเตอร์จะเกี่ยวข้องกับเรื่องของตัวเลข. คอมพิวเตอร์จัดเก็บตัวอักษรและอักขระอื่นๆ" + + " โดยการกำหนดหมายเลขให้สำหรับแต่ละตัว. ก่อนหน้าที่๊ Unicode จะถูกสร้างขึ้น, ได้มีระบบ encoding " + + "อยู่หลายร้อยระบบสำหรับการกำหนดหมายเลขเหล่านี้. ไม่มี encoding ใดที่มีจำนวนตัวอักขระมากเพียงพอ: ยกตัวอย่างเช่น, " + + "เฉพาะในกลุ่มสหภาพยุโรปเพียงแห่งเดียว ก็ต้องการหลาย encoding ในการครอบคลุมทุกภาษาในกลุ่ม. " + + "หรือแม้แต่ในภาษาเดี่ยว เช่น ภาษาอังกฤษ ก็ไม่มี encoding ใดที่เพียงพอสำหรับทุกตัวอักษร, " + + "เครื่องหมายวรรคตอน และสัญลักษณ์ทางเทคนิคที่ใช้กันอยู่ทั่วไป.\n" + + "ระบบ encoding เหล่านี้ยังขัดแย้งซึ่งกันและกัน. นั่นก็คือ, ในสอง encoding สามารถใช้หมายเลขเดียวกันสำหรับตัวอักขระสองตัวที่แตกต่างกัน," + + "หรือใช้หมายเลขต่างกันสำหรับอักขระตัวเดียวกัน. ในระบบคอมพิวเตอร์ (โดยเฉพาะเซิร์ฟเวอร์) ต้องมีการสนับสนุนหลาย" + + " encoding; และเมื่อข้อมูลที่ผ่านไปมาระหว่างการเข้ารหัสหรือแพล็ตฟอร์มที่ต่างกัน, ข้อมูลนั้นจะเสี่ยงต่อการผิดพลาดเสียหาย."; + + T13512Thread t1 = new T13512Thread(thai); + T13512Thread t2 = new T13512Thread(japanese); + try { + t1.start(); t2.start(); + t1.join(); t2.join(); + } catch (Exception e) { + fail(e.toString()); + } + assertEquals("", t1.fExpectedBoundaries, t1.fBoundaries); + assertEquals("", t2.fExpectedBoundaries, t2.fBoundaries); + } } diff --git a/android_icu4j/src/main/tests/android/icu/dev/test/util/DebugUtilitiesData.java b/android_icu4j/src/main/tests/android/icu/dev/test/util/DebugUtilitiesData.java index a34f7838b..0354ddbe2 100644 --- a/android_icu4j/src/main/tests/android/icu/dev/test/util/DebugUtilitiesData.java +++ b/android_icu4j/src/main/tests/android/icu/dev/test/util/DebugUtilitiesData.java @@ -14,7 +14,7 @@ import android.icu.testsharding.MainTestShard; @MainTestShard public class DebugUtilitiesData extends Object { - public static final String ICU4C_VERSION="60.1"; + public static final String ICU4C_VERSION="60.2"; public static final int UDebugEnumType = 0; public static final int UCalendarDateFields = 1; public static final int UCalendarMonths = 2; |