]> granicus.if.org Git - icu/commitdiff
ICU-20436 Add getDefaultHourCycle to DateTimePatternGenerator
authorFrank Tang <ftang@chromium.org>
Wed, 11 Dec 2019 20:24:50 +0000 (20:24 +0000)
committerFrank Yung-Fong Tang <41213225+FrankYFTang@users.noreply.github.com>
Thu, 12 Dec 2019 08:13:37 +0000 (00:13 -0800)
See #901

icu4c/source/i18n/dtptngen.cpp
icu4c/source/i18n/udatpg.cpp
icu4c/source/i18n/unicode/dtptngen.h
icu4c/source/i18n/unicode/udat.h
icu4c/source/i18n/unicode/udatpg.h
icu4c/source/test/cintltst/udatpg_test.c
icu4c/source/test/intltest/dtptngts.cpp
icu4j/main/classes/core/src/com/ibm/icu/text/DateFormat.java
icu4j/main/classes/core/src/com/ibm/icu/text/DateTimePatternGenerator.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateTimeGeneratorTest.java

index 4948d2cbc97f9309a69456b427416865c5c6e70f..09faf5bb6ccd585f31ee3091b1509f8c889a8b66 100644 (file)
@@ -687,6 +687,22 @@ void DateTimePatternGenerator::getAllowedHourFormats(const Locale &locale, UErro
     }
 }
 
+UDateFormatHourCycle
+DateTimePatternGenerator::getDefaultHourCycle(UErrorCode& /*status*/) const {
+  switch(fDefaultHourFormatChar) {
+    case CAP_K:
+      return UDAT_HOUR_CYCLE_11;
+    case LOW_H:
+      return UDAT_HOUR_CYCLE_12;
+    case CAP_H:
+      return UDAT_HOUR_CYCLE_23;
+    case LOW_K:
+      return UDAT_HOUR_CYCLE_24;
+    default:
+      UPRV_UNREACHABLE;
+  }
+}
+
 UnicodeString
 DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode&
 /*status*/) {
index febf73b3ce499fdcaf4ea3504d80bc1a7f8bed63..332636a93889f15c572dbe73cca58fca624209ed 100644 (file)
@@ -291,4 +291,9 @@ udatpg_getPatternForSkeleton(const UDateTimePatternGenerator *dtpg,
     return result.getBuffer();
 }
 
+U_CAPI UDateFormatHourCycle U_EXPORT2
+udatpg_getDefaultHourCycle(const UDateTimePatternGenerator *dtpg, UErrorCode* pErrorCode) {
+    return ((const DateTimePatternGenerator *)dtpg)->getDefaultHourCycle(*pErrorCode);
+}
+
 #endif
index a71938b31cf5d8279a29110109cf7a329589041e..af74059c745cc004c77c18694f5a59c6eaa11414 100644 (file)
@@ -483,6 +483,17 @@ public:
      */
     const UnicodeString& getDecimal() const;
 
+#ifndef U_HIDE_DRAFT_API
+    /**
+     * Get the default hour cycle.
+     * @param status  Output param set to success/failure code on exit,
+     *               which must not indicate a failure before the function call.
+     * @return the default hour cycle.
+     * @draft ICU 67
+     */
+    UDateFormatHourCycle getDefaultHourCycle(UErrorCode& status) const;
+#endif  /* U_HIDE_DRAFT_API */
+
     /**
      * ICU "poor man's RTTI", returns a UClassID for the actual class.
      *
index bdbd080c0058218141ba89ca10687790b893bf83..cf7a165e70ab4f85e7aba3acd381cf3f4b275a32 100644 (file)
@@ -958,7 +958,37 @@ udat_getBooleanAttribute(const UDateFormat* fmt, UDateFormatBooleanAttribute att
 U_CAPI void U_EXPORT2
 udat_setBooleanAttribute(UDateFormat *fmt, UDateFormatBooleanAttribute attr, UBool newValue, UErrorCode* status);
 
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Hour Cycle.
+ * @draft ICU 67
+ */
+typedef enum UDateFormatHourCycle {
+    /**
+     * Hour in am/pm (0~11)
+     * @draft ICU 67
+     */
+    UDAT_HOUR_CYCLE_11,
+
+    /**
+     * Hour in am/pm (1~12)
+     * @draft ICU 67
+     */
+    UDAT_HOUR_CYCLE_12,
+
+    /**
+     * Hour in day (0~23)
+     * @draft ICU 67
+     */
+    UDAT_HOUR_CYCLE_23,
 
+    /**
+     * Hour in day (1~24)
+     * @draft ICU 67
+     */
+    UDAT_HOUR_CYCLE_24
+} UDateFormatHourCycle;
+#endif  /* U_HIDE_DRAFT_API */
 
 #if U_SHOW_CPLUSPLUS_API
 
index 7f28b5a31978f20c78dd4e5a0caa14fafa3db1f1..2b3982894264f0622b1b69d283420cf8ba1077d0 100644 (file)
@@ -20,6 +20,7 @@
 #define __UDATPG_H__
 
 #include "unicode/utypes.h"
+#include "unicode/udat.h"
 #include "unicode/uenum.h"
 #include "unicode/localpointer.h"
 
@@ -651,4 +652,18 @@ udatpg_getPatternForSkeleton(const UDateTimePatternGenerator *dtpg,
                              const UChar *skeleton, int32_t skeletonLength,
                              int32_t *pLength);
 
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Return the default hour cycle.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ *                   failure before the function call.
+ * @return the default hour cycle.
+ * @draft ICU 67
+ */
+U_DRAFT UDateFormatHourCycle U_EXPORT2
+udatpg_getDefaultHourCycle(const UDateTimePatternGenerator *dtpg, UErrorCode* pErrorCode);
+#endif  /* U_HIDE_DRAFT_API */
+
 #endif
index 2338a2f687faeba9d772a321322aa208fd62cc6e..b7d8cd79ed9c984f0d2f7207b75e287d64f729ea 100644 (file)
@@ -43,6 +43,7 @@ static void TestUsage(void);
 static void TestBuilder(void);
 static void TestOptions(void);
 static void TestGetFieldDisplayNames(void);
+static void TestGetDefaultHourCycle(void);
 
 void addDateTimePatternGeneratorTest(TestNode** root) {
     TESTCASE(TestOpenClose);
@@ -50,6 +51,7 @@ void addDateTimePatternGeneratorTest(TestNode** root) {
     TESTCASE(TestBuilder);
     TESTCASE(TestOptions);
     TESTCASE(TestGetFieldDisplayNames);
+    TESTCASE(TestGetDefaultHourCycle);
 }
 
 /*
@@ -510,4 +512,46 @@ static void TestGetFieldDisplayNames() {
     }
 }
 
+typedef struct HourCycleData {
+    const char *         locale;
+    UDateFormatHourCycle   expected;
+} HourCycleData;
+
+static void TestGetDefaultHourCycle() {
+    const HourCycleData testData[] = {
+        /*loc      expected */
+        { "ar_EG",    UDAT_HOUR_CYCLE_12 },
+        { "de_DE",    UDAT_HOUR_CYCLE_23 },
+        { "en_AU",    UDAT_HOUR_CYCLE_12 },
+        { "en_CA",    UDAT_HOUR_CYCLE_12 },
+        { "en_US",    UDAT_HOUR_CYCLE_12 },
+        { "es_ES",    UDAT_HOUR_CYCLE_23 },
+        { "fi",       UDAT_HOUR_CYCLE_23 },
+        { "fr",       UDAT_HOUR_CYCLE_23 },
+        { "ja_JP",    UDAT_HOUR_CYCLE_23 },
+        { "zh_CN",    UDAT_HOUR_CYCLE_12 },
+        { "zh_HK",    UDAT_HOUR_CYCLE_12 },
+        { "zh_TW",    UDAT_HOUR_CYCLE_12 },
+        { "ko_KR",    UDAT_HOUR_CYCLE_12 },
+    };
+    int count = UPRV_LENGTHOF(testData);
+    const HourCycleData * testDataPtr = testData;
+    for (; count-- > 0; ++testDataPtr) {
+        UErrorCode status = U_ZERO_ERROR;
+        UDateTimePatternGenerator * dtpgen =
+            udatpg_open(testDataPtr->locale, &status);
+        if ( U_FAILURE(status) ) {
+            log_data_err( "ERROR udatpg_open failed for locale %s : %s - (Are you missing data?)\n",
+                         testDataPtr->locale, myErrorName(status));
+        } else {
+            UDateFormatHourCycle actual = udatpg_getDefaultHourCycle(dtpgen, &status);
+            if (U_FAILURE(status) || testDataPtr->expected != actual) {
+                log_err("ERROR dtpgen locale %s udatpg_getDefaultHourCycle expecte to get %d but get %d\n",
+                        testDataPtr->locale, testDataPtr->expected, actual);
+            }
+            udatpg_close(dtpgen);
+        }
+    }
+}
+
 #endif
index 02745c12a2f189c9a52d94ef6a6690bb53d15f40..0a9c5eaf9b3dfac057581924396b31ea13507993 100644 (file)
@@ -1410,18 +1410,19 @@ void IntlTestDateTimePatternGeneratorAPI::test20640_HourCyclArsEnNH() {
         const char* localeName;
         const char16_t* expectedDtpgPattern;
         const char16_t* expectedTimePattern;
+        UDateFormatHourCycle expectedDefaultHourCycle;
     } cases[] = {
         // ars is interesting because it does not have a region, but it aliases
         // to ar_SA, which has a region.
-        {"ars", u"h a", u"h:mm a"},
+        {"ars", u"h a", u"h:mm a", UDAT_HOUR_CYCLE_12},
         // en_NH is interesting because NH is a deprecated region code;
         // formerly New Hebrides, now Vanuatu => VU => h.
-        {"en_NH", u"h a", u"h:mm a"},
+        {"en_NH", u"h a", u"h:mm a", UDAT_HOUR_CYCLE_12},
         // ch_ZH is a typo (should be zh_CN), but we should fail gracefully.
         // {"cn_ZH", u"HH", u"H:mm"}, // TODO(ICU-20653): Desired behavior
-        {"cn_ZH", u"HH", u"h:mm a"}, // Actual behavior
+        {"cn_ZH", u"HH", u"h:mm a", UDAT_HOUR_CYCLE_23 }, // Actual behavior
         // a non-BCP47 locale without a country code should not fail
-        {"ja_TRADITIONAL", u"H時", u"H:mm"},
+        {"ja_TRADITIONAL", u"H時", u"H:mm", UDAT_HOUR_CYCLE_23},
     };
 
     for (auto& cas : cases) {
@@ -1440,11 +1441,17 @@ void IntlTestDateTimePatternGeneratorAPI::test20640_HourCyclArsEnNH() {
         if (status.errIfFailureAndReset()) {
             return;
         }
+        UDateFormatHourCycle defaultHourCycle = dtpg->getDefaultHourCycle(status);
+        if (status.errIfFailureAndReset()) {
+            return;
+        }
 
         assertEquals(UnicodeString("dtpgPattern ") + cas.localeName,
             cas.expectedDtpgPattern, dtpgPattern);
         assertEquals(UnicodeString("timePattern ") + cas.localeName,
             cas.expectedTimePattern, timePattern);
+        assertEquals(UnicodeString("defaultHour ") + cas.localeName,
+            cas.expectedDefaultHourCycle, defaultHourCycle);
     }
 
 }
index 5eb207e189bb80aea7389d24d11e3b4d8eda07cb..bd42fbd4bf715a4cb376d1ee4a46706a63fd69a7 100644 (file)
@@ -535,6 +535,36 @@ public abstract class DateFormat extends UFormat {
      */
     private EnumSet<BooleanAttribute> booleanAttributes = EnumSet.allOf(BooleanAttribute.class);
 
+    /**
+     * Hour Cycle
+     * @draft ICU 67
+     */
+    public enum HourCycle {
+        /**
+         * hour in am/pm (0~11)
+         * @draft ICU 67
+         */
+        HOUR_CYCLE_11,
+
+        /**
+         * hour in am/pm (1~12)
+         * @draft ICU 67
+         */
+        HOUR_CYCLE_12,
+
+        /**
+         * hour in day (0~23)
+         * @draft ICU 67
+         */
+        HOUR_CYCLE_23,
+
+        /**
+         * hour in day (1~24)
+         * @draft ICU 67
+         */
+        HOUR_CYCLE_24;
+    };
+
     /*
      * Capitalization setting, hoisted to DateFormat ICU 53
      * Note that SimpleDateFormat serialization may call getContext/setContext to read/write
index eb233181a693fc882c39364eb6dcb27202f5fe39..96becb5c770c4c752c36f4dbf15646e0b5dbf6fd 100644 (file)
@@ -1205,7 +1205,6 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
     private static final int APPENDITEM_WIDTH_INT = APPENDITEM_WIDTH.ordinal();
     private static final DisplayWidth[] CLDR_FIELD_WIDTH = DisplayWidth.values();
 
-
     // Option masks for getBestPattern, replaceFieldTypes (individual masks may be ORed together)
 
     /**
@@ -1313,6 +1312,20 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
         return getFieldDisplayName(field, APPENDITEM_WIDTH);
     }
 
+    /**
+     * Return the default hour cycle.
+     * @draft ICU 67
+     */
+    public DateFormat.HourCycle getDefaultHourCycle() {
+      switch(getDefaultHourFormatChar()) {
+        case 'h': return DateFormat.HourCycle.HOUR_CYCLE_12;
+        case 'H': return DateFormat.HourCycle.HOUR_CYCLE_23;
+        case 'k': return DateFormat.HourCycle.HOUR_CYCLE_24;
+        case 'K': return DateFormat.HourCycle.HOUR_CYCLE_11;
+        default: throw new AssertionError("should be unreachable");
+      }
+    }
+
     /**
      * The private interface to set a display name for a particular date/time field,
      * in one of several possible display widths.
index 767bb60ef26d16276ace6ae602911d82f5d006dc..d7188b7f4d9222c34fd067a328882ecb1034f725 100644 (file)
@@ -1733,14 +1733,14 @@ public class DateTimeGeneratorTest extends TestFmwk {
         String[][] cases = new String[][]{
             // ars is interesting because it does not have a region, but it aliases
             // to ar_SA, which has a region.
-            {"ars", "h a", "h:mm a"},
+            {"ars", "h a", "h:mm a", "HOUR_CYCLE_12"},
             // en_NH is interesting because NH is a depregated region code.
-            {"en_NH", "h a", "h:mm a"},
+            {"en_NH", "h a", "h:mm a", "HOUR_CYCLE_12"},
             // ch_ZH is a typo (should be zh_CN), but we should fail gracefully.
             // {"cn_ZH", "HH", "H:mm"}, // TODO(ICU-20653): Desired behavior
-            {"cn_ZH", "HH", "h:mm a"}, // Actual behavior
+            {"cn_ZH", "HH", "h:mm a", "HOUR_CYCLE_23"}, // Actual behavior
             // a non-BCP47 locale without a country code should not fail
-            {"ja_TRADITIONAL", "H時", "H:mm"},
+            {"ja_TRADITIONAL", "H時", "H:mm", "HOUR_CYCLE_23"},
         };
 
         for (String[] cas : cases) {
@@ -1755,6 +1755,8 @@ public class DateTimeGeneratorTest extends TestFmwk {
                 cas[1], dtpgPattern);
             assertEquals("timePattern " + cas[1],
                 cas[2], timePattern);
+            assertEquals("default hour cycle " + cas[3],
+                cas[3], dtpg.getDefaultHourCycle().toString());
         }
     }
 }