LQA: Time of day is written with a “dot” not a “colon” (13.14 not 13:14)

来源:互联网 发布:冬不拉教程软件 编辑:程序博客网 时间:2024/05/20 06:31

关键 log

I/ConsoleReporter: [1/1 armeabi-v7a CtsIcuTestCases HZC75C7N] android.icu.dev.test.format.DateTimeGeneratorTest#TestOptions fail: junit.framework.AssertionFailedError: Failure: TestOptions(android.icu.dev.test.format.DateTimeGeneratorTest), due to 6 error(s)Error: (DateTimeGeneratorTest.java:1249) Locale da, skeleton Hmm, options ==0, expected pattern HH.mm, got HH:mmError: (DateTimeGeneratorTest.java:1249) Locale da, skeleton HHmm, options ==0, expected pattern HH.mm, got HH:mmError: (DateTimeGeneratorTest.java:1249) Locale da, skeleton hhmm, options ==0, expected pattern h.mm a, got h:mm aError: (DateTimeGeneratorTest.java:1249) Locale da, skeleton Hmm, options !=0, expected pattern H.mm, got H:mmError: (DateTimeGeneratorTest.java:1249) Locale da, skeleton HHmm, options !=0, expected pattern HH.mm, got HH:mmError: (DateTimeGeneratorTest.java:1249) Locale da, skeleton hhmm, options !=0, expected pattern hh.mm a, got hh:mm aat android.icu.junit.IcuFrameworkTest.test_for_TestFmwk_Run(IcuFrameworkTest.java:117)at android.icu.junit.IcuFrameworkTest.run(IcuFrameworkTest.java:63)at android.icu.junit.IcuTestFmwkRunner$2.evaluate(IcuTestFmwkRunner.java:126)at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)at android.icu.junit.IcuTestFmwkRunner.runChild(IcuTestFmwkRunner.java:130)at android.icu.junit.IcuTestFmwkRunner.runChild(IcuTestFmwkRunner.java:117)at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)

此问题首先分析 log 可以看到 DateTimeGeneratorTest 文件 1249 打印出来的报错信息,通过 openGrok 搜索一下,然后看1249

/alps/external/icu/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateTimeGeneratorTest.java..........   private final class TestOptionsItem {         public String locale;         public String skeleton;         public String expectedPattern;         public int options;          // Simple constructor         public TestOptionsItem(String loc, String skel, String expectedPat, int opts) {             locale = loc;             skeleton = skel;              expectedPattern = expectedPat;              options = opts;          }      }      public void TestOptions() {         final TestOptionsItem[] testOptionsData = {              new TestOptionsItem( "en", "Hmm",  "HH:mm",   DateTimePatternGenerator.MATCH_NO_OPTIONS        ),              new TestOptionsItem( "en", "HHmm", "HH:mm",   DateTimePatternGenerator.MATCH_NO_OPTIONS        ),              new TestOptionsItem( "en", "hhmm", "h:mm a",  DateTimePatternGenerator.MATCH_NO_OPTIONS        ),              new TestOptionsItem( "en", "Hmm",  "HH:mm",   DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),              new TestOptionsItem( "en", "HHmm", "HH:mm",   DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),              new TestOptionsItem( "en", "hhmm", "hh:mm a", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),              new TestOptionsItem( "da", "Hmm",  "HH.mm",   DateTimePatternGenerator.MATCH_NO_OPTIONS        ),              new TestOptionsItem( "da", "HHmm", "HH.mm",   DateTimePatternGenerator.MATCH_NO_OPTIONS        ),              new TestOptionsItem( "da", "hhmm", "h.mm a",  DateTimePatternGenerator.MATCH_NO_OPTIONS        ),              new TestOptionsItem( "da", "Hmm",  "H.mm",    DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),              new TestOptionsItem( "da", "HHmm", "HH.mm",   DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),              new TestOptionsItem( "da", "hhmm", "hh.mm a", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ),              //              new TestOptionsItem( "en",                   "yyyy",  "yyyy",  DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en",                   "YYYY",  "YYYY",  DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en",                   "U",     "y",     DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en@calendar=japanese", "yyyy",  "y G",   DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en@calendar=japanese", "YYYY",  "Y G",   DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en@calendar=japanese", "U",     "y G",   DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en@calendar=chinese",  "yyyy",  "r(U)",     DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en@calendar=chinese",  "YYYY",  "Y(Y)",     DateTimePatternGenerator.MATCH_NO_OPTIONS ), // not a good result, want r(Y) or r(U)              new TestOptionsItem( "en@calendar=chinese",  "U",     "r(U)",     DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en@calendar=chinese",  "Gy",    "r(U)",     DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en@calendar=chinese",  "GU",    "r(U)",     DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en@calendar=chinese",  "ULLL",  "MMM U",    DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en@calendar=chinese",  "yMMM",  "MMM r(U)", DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "en@calendar=chinese",  "GUMMM", "MMM r(U)", DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "zh@calendar=chinese",  "yyyy",  "rU\u5E74",    DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "zh@calendar=chinese",  "YYYY",  "YY\u5E74",    DateTimePatternGenerator.MATCH_NO_OPTIONS ), // not a good result, want r(Y) or r(U)              new TestOptionsItem( "zh@calendar=chinese",  "U",     "rU\u5E74",    DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "zh@calendar=chinese",  "Gy",    "rU\u5E74",    DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "zh@calendar=chinese",  "GU",    "rU\u5E74",    DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "zh@calendar=chinese",  "ULLL",  "U\u5E74MMM",  DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "zh@calendar=chinese",  "yMMM",  "rU\u5E74MMM", DateTimePatternGenerator.MATCH_NO_OPTIONS ),              new TestOptionsItem( "zh@calendar=chinese",  "GUMMM", "rU\u5E74MMM", DateTimePatternGenerator.MATCH_NO_OPTIONS ),          };          for (int i = 0; i < testOptionsData.length; ++i) {              // 这里可以看到用  locale 参数 创建了一个  ULocale,  这个东西首先不看的话 也能猜到 基本就是一个 Locale 一些参数配置的存放类              //关键类位置 alps/external/icu/icu4j/main/classes/core/src/com/ibm/icu/util/ULocale.java              ULocale uloc = new ULocale(testOptionsData[i].locale);          // 根据  uloc 对象,去创建  Pattern, 这个就有点像我们的正则了吧,(这里就是重点了, 去看一下他是怎么创建这个匹配方式的)              DateTimePatternGenerator dtpgen = DateTimePatternGenerator.getInstance(uloc);          String pattern = dtpgen.getBestPattern(testOptionsData[i].skeleton, testOptionsData[i].options);          if (pattern.compareTo(testOptionsData[i].expectedPattern) != 0) {              //在这里报错了  输出了error的信息                  errln("Locale " + testOptionsData[i].locale + ", skeleton " + testOptionsData[i].skeleton +                      ", options " + ((testOptionsData[i].options != 0)? "!=0": "==0") +                      ", expected pattern " + testOptionsData[i].expectedPattern + ", got " + pattern);             }        }  }

可以看到log 是 Locale da, skeleton Hmm, options ==0, expected pattern HH.mm, got HH:mm
所以是中间 定义的 local 为 ‘da’ 的项

继续看格式化正则那里的代码跟进去

/alps/external/icu/icu4j/main/classes/core/src/com/ibm/icu/text/DateTimePatternGenerator.java..........   public static DateTimePatternGenerator getInstance(ULocale uLocale) {        return getFrozenInstance(uLocale).cloneAsThawed();    } @Deprecated    public static DateTimePatternGenerator getFrozenInstance(ULocale uLocale) {        String localeKey = uLocale.toString();        DateTimePatternGenerator result = DTPNG_CACHE.get(localeKey);        if (result != null) {            return result;        }        result = new DateTimePatternGenerator();        PatternInfo returnInfo = new PatternInfo();        String shortTimePattern = null;       // first load with the ICU patterns        for (int i = DateFormat.FULL; i <= DateFormat.SHORT; ++i) {            // 其他的都不看了就看这一句, 是调用 android 系统提供的方法 根据 区域,获得这个时间格式的 Format            SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(i, uLocale);        // 然后 添加这个规则        result.addPattern(df.toPattern(), false, returnInfo);            df = (SimpleDateFormat) DateFormat.getTimeInstance(i, uLocale);            result.addPattern(df.toPattern(), false, returnInfo);            if (i == DateFormat.SHORT) {                // keep this pattern to populate other time field               // combination patterns by hackTimes later in this method.                shortTimePattern = df.toPattern();                // use hour style in SHORT time pattern as the default                // hour style for the locale                FormatParser fp = new FormatParser();               fp.set(shortTimePattern);                List<Object> items = fp.getItems();               for (int idx = 0; idx < items.size(); idx++) {                    Object item = items.get(idx);                    if (item instanceof VariableField) {                        VariableField fld = (VariableField)item;                        if (fld.getType() == HOUR) {                           result.defaultHourFormatChar = fld.toString().charAt(0);                           break;                        }                   }               }         }    .......    ......

所以说, 就肯定是对语言格式或者什么的修改, 违背了android 不同国家下的默认规则 的原则
最后查看 git 记录,确实有一个修改,修改了一个国家下的时间显示格
修改了丹麦语, 中 时间的显示格式

http://www.icu-project.org/apiref/icu4c/classicu_1_1DateTimePatternGenerator.html

http://www.icu-project.org/apiref/icu4c/classes.html

几种修改方式

0. 修改时间格式 分隔符
在文件中修改

gregorian{            AmPmMarkers{                "AM",                "PM",            }            DateTimePatterns{                "h:mm:ss a zzzz",  //变成  "h.mm.ss a zzzz"                "h:mm:ss a z",  // "h.mm.ss a z",                "h:mm:ss a",    // "h.mm.ss a",                "h:mm a",

1.:将中文环境下的日期格式修改为”yyyy年 M月 d日,EEE”(EEE是星期)

L:
打开文件Donottranslate-cldr.xml (frameworks\base\core\res\res\values-zh-rcn)
找到numeric_date_format这项,修改成下面这样:

 <string name="numeric_date_format">yyyy年 M月 d日,EEE</string>

这样默认日期格式就变成“yyyy年 M月 d日,EEE”了。
kk:
对于KK版本,这个格式使用的是底层ICU的定义
如是英文的定义的如下

android L 路径 external\icu\icu4c\source\data\locales\en.txt
android KK 路径 external/icu4c/locales/en.txt

gregorian{            AmPmMarkers{                "AM",                "PM",            }            DateTimePatterns{                "h:mm:ss a zzzz",                "h:mm:ss a z",                "h:mm:ss a",                "h:mm a",                "EEEE, MMMM d, y",                "MMMM d, y",                "MMM d, y",                "m/d/yy"  //修改此处,如改为d/y/MMM                "{1},{0}"

对于希伯来语、印尼语以及意地绪语上层使用的语言编码和ICU定义的不同,要改的文件分别是:
希伯来语:he.txt
印尼语:id.txt
意地绪语:yi.txt

丹麦语: da.txt
波斯语: fa.txt

2. 如果没有设置默认系统的时间显示格式(12小时制或者24小时制),系统切换不同语言显示时间格式是不同的,

波斯语是24小时制,中文是12小时制,这是在哪里控制的呢?

这是icu的时间格式觉定的“H”代表24小时制,“h”代表12小时制,如波斯语如下
android kk external\icu4c\data\locales\fa.txt
android L external\icu\icu4c\source\data\locales\fa.txt

gregorian{            ....            DateTimePatterns{                "H:mm:ss (zzzz)",                "H:mm:ss (z)",                "H:mm:ss",                "H:mm",                "EEEE d MMMM y",                "d MMMM y",                "d MMM y",                "y/M/d",                ...        ....            }如果改成12小时制的话,只需把上面红色部分改成下面就行               "H:mm:ss (zzzz)",                "h:mm:ss (z)",                "h:mm:ss",                "h:mm",

还有好多其他的修改,还要编译 icu资源文件的方式等等,这里只是分析这个cts问题。

1 0
原创粉丝点击