]> granicus.if.org Git - icu/commitdiff
ICU-10320 API for getting/setting number format override in date formatting
authorTom Zhang <tomzhang@svn.icu-project.org>
Fri, 25 Jul 2014 16:55:56 +0000 (16:55 +0000)
committerTom Zhang <tomzhang@svn.icu-project.org>
Fri, 25 Jul 2014 16:55:56 +0000 (16:55 +0000)
X-SVN-Rev: 36086

icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java

index 475e3a7183b2fbc5110cecc11aad0007da3e633a..d12b116437c1a9481cd8bee2a2bb240159f06bdd 100644 (file)
@@ -21,6 +21,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.MissingResourceException;
+import java.util.UUID;
 
 import com.ibm.icu.impl.CalendarData;
 import com.ibm.icu.impl.DateNumberFormat;
@@ -1967,7 +1968,10 @@ public class SimpleDateFormat extends DateFormat {
     }
 
     /**
-     * Overrides superclass method
+     * Overrides superclass method and
+     * This method also clears per field NumberFormat instances 
+     * previously set by {@link #setNumberFormat(String, NumberFormat)} 
+     * 
      * @stable ICU 2.0
      */
     public void setNumberFormat(NumberFormat newNumberFormat) {
@@ -1975,6 +1979,13 @@ public class SimpleDateFormat extends DateFormat {
         super.setNumberFormat(newNumberFormat);
         initLocalZeroPaddingNumberFormat();
         initializeTimeZoneFormat(true);
+
+        if (numberFormatters != null) {
+            numberFormatters = null;
+        }
+        if (overrideMap != null) {
+            overrideMap = null;
+        }
     }
 
     private void initLocalZeroPaddingNumberFormat() {
@@ -3901,21 +3912,64 @@ public class SimpleDateFormat extends DateFormat {
     }
 
     /**
-     * @internal
-     * @deprecated This API is ICU internal only.
+     * allow the user to set the NumberFormat for several fields
+     * It can be a single field like: "y"(year) or "M"(month)
+     * It can be several field combined together: "yMd"(year, month and date)
+     * Note: 
+     * 1 symbol field is enough for multiple symbol fields (so "y" will override "yy", "yyy")
+     * If the field is not numeric, then override has no effect (like "MMM" will use abbreviation, not numerical field)
+     * 
+     * @param fields the fields to override
+     * @param overrideNF the NumbeferFormat used 
+     * @exception IllegalArgumentException when the fields contain invalid field
+     * @draft ICU 54
+     * @provisional This API might change or be removed in a future release.
      */
-    @Deprecated
-    protected NumberFormat getNumberFormat(char ch) {
+    public void setNumberFormat(String fields, NumberFormat overrideNF) {
+        overrideNF.setGroupingUsed(false);
+        String nsName = "$" + UUID.randomUUID().toString();
+        
+        // initialize mapping if not there
+        if (numberFormatters == null) {
+            numberFormatters = new HashMap<String, NumberFormat>();
+        }
+        if (overrideMap == null) {
+            overrideMap = new HashMap<Character, String>();
+        }
 
-       Character ovrField;
-       ovrField = Character.valueOf(ch);
-       if (overrideMap != null && overrideMap.containsKey(ovrField)) {
-           String nsName = overrideMap.get(ovrField).toString();
-           NumberFormat nf = numberFormatters.get(nsName);
-           return nf;
-       } else {
-           return numberFormat;
-       }
+        // separate string into char and add to maps
+        for (int i = 0; i < fields.length(); i++) {
+            char field = fields.charAt(i);
+            if (DateFormatSymbols.patternChars.indexOf(field) == -1) {
+                throw new IllegalArgumentException("Illegal field character " + "'" + field + "' in setNumberFormat.");
+            }
+            overrideMap.put(field, nsName);
+            numberFormatters.put(nsName, overrideNF);
+        }
+
+        // Since one or more of the override number formatters might be complex,
+        // we can't rely on the fast numfmt where we have a partial field override.
+        useLocalZeroPaddingNumberFormat = false;
+    }
+    
+    /**
+     * give the NumberFormat used for the field like 'y'(year) and 'M'(year)
+     *
+     * @param field the field the user wants
+     * @return override NumberFormat used for the field
+     * @draft ICU 54
+     * @provisional This API might change or be removed in a future release.
+     */
+    public NumberFormat getNumberFormat(char field) {
+        Character ovrField;
+        ovrField = Character.valueOf(field);
+        if (overrideMap != null && overrideMap.containsKey(ovrField)) {
+            String nsName = overrideMap.get(ovrField).toString();
+            NumberFormat nf = numberFormatters.get(nsName);
+            return nf;
+        } else {
+            return numberFormat;
+        }
     }
 
     private void initNumberFormatters(ULocale loc) {
@@ -3971,7 +4025,7 @@ public class SimpleDateFormat extends DateFormat {
                 useLocalZeroPaddingNumberFormat = false;
             }
 
-            if (!numberFormatters.containsKey(nsName)) {
+            if (!fullOverride && !numberFormatters.containsKey(nsName)) {
                   numberFormatters.put(nsName,nf);
             }
 
index 0c68e4d3baf350dc0a65b2a3ce4caa1c64153c2d..939e3daae50612fc5cee9a7723704669a8687dce 100644 (file)
@@ -3898,6 +3898,65 @@ public class DateFormatTest extends com.ibm.icu.dev.test.TestFmwk {
             errln("FAIL: parsed -> " + parsedate.toString() + " expected -> " + cal.toString()); 
         }
     } 
+    
+    public void TestOverrideNumberForamt() {
+        SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yy z");
+
+        // test override get/set NumberFormat
+        for (int i = 0; i < 100; i++) {
+            NumberFormat check_nf = NumberFormat.getInstance(new ULocale("en_US"));
+            fmt.setNumberFormat("y", check_nf);
+            NumberFormat get_nf = fmt.getNumberFormat('y');
+            if (!get_nf.equals(check_nf))
+                errln("FAIL: getter and setter do not work");
+        }
+
+        NumberFormat reused_nf = NumberFormat.getInstance(new ULocale("en_US"));
+        fmt.setNumberFormat("y", reused_nf);
+        fmt.setNumberFormat(reused_nf); // test the same override NF will not crash
+
+        // DATA[i][0] is to tell which field to set, DATA[i][1] is the expected result
+        String[][] DATA = { 
+                { "", "\u521D\u516D \u5341\u4E94" }, 
+                { "M", "\u521D\u516D 15" },
+                { "Mo", "\u521D\u516D \u5341\u4E94" }, 
+                { "Md", "\u521D\u516D \u5341\u4E94" }, 
+                { "MdMMd", "\u521D\u516D \u5341\u4E94" }, 
+                { "mixed", "\u521D\u516D \u5341\u4E94" }, 
+        };
+
+        NumberFormat override = NumberFormat.getInstance(new ULocale("en@numbers=hanidays"));
+        Calendar cal = Calendar.getInstance();
+        cal.set(1997, Calendar.JUNE, 15);
+        Date test_date = cal.getTime();
+        
+        for (int i = 0; i < DATA.length; i++) {
+            fmt = new SimpleDateFormat("MM d", new ULocale("en_US"));
+            String field = DATA[i][0];
+            
+            if (field == "") { // use the one w/o field
+                fmt.setNumberFormat(override);
+            } else if (field == "mixed") { // set 1 field at first but then full override, both(M & d) should be override
+                NumberFormat single_override = NumberFormat.getInstance(new ULocale("en@numbers=hebr"));
+                fmt.setNumberFormat("M", single_override);
+                fmt.setNumberFormat(override);
+            } else if (field == "Mo") { // o is invalid field
+                try {
+                    fmt.setNumberFormat(field, override);
+                } catch (IllegalArgumentException e) {
+                    logln("IllegalArgumentException is thrown for invalid fields");
+                    continue;
+                }
+            } else {
+                fmt.setNumberFormat(field, override);
+            }
+            String result = fmt.format(test_date);
+            String expected  = DATA[i][1];
+
+            if (!result.equals(expected))
+                errln((String) "FAIL: -> " + result.toString() + " expected -> " + expected);
+        }
+    }
 
     public void TestParsePosition() {
         class ParseTestData {