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问题。
- LQA: Time of day is written with a “dot” not a “colon” (13.14 not 13:14)
- A class file not written.
- Support for specifying both a day-of-week AND a day-of-month parameter is not implemented
- hdu4028The time of a day
- 'daemonize' is not a member of 'ACE'
- 'GetCurSel' : is not a member of 'CTime'
- is not a member of global namespace
- 'WriteHuge' : is not a member of 'CFile'
- 'find_if’ is not a member of ‘std'
- 'SetWindowTextA' : is not a member of 'CString'
- 'numeric_limits' is not a member of 'std'|
- 'numeric_limits' is not a member of 'std'
- 'putText' is not a member of 'cv'
- '_file': is not a member of '_iobuf'
- A class file was not written.
- A class file was not written.
- ERROR:A class was not written.
- A class file was not written解决方法
- 【数据结构】-线性表-顺序表-1325: 算法2-3~2-6:Big Bang【麻烦】
- 2016思考的三个问题
- Gif合成透明PNG变成黑色背景GIF问题解决
- 用PHP创建一个REST APi
- GCD 保持iOS app后台长时间运行
- LQA: Time of day is written with a “dot” not a “colon” (13.14 not 13:14)
- AOP
- Eclipse 个人配置
- 搜索引擎“年底数据大更新”究竟持续多长时间?届时对那些网站造成严重影响?
- Codeforces 757B Bash's Big Day 【数论】
- Reclerview下拉刷新,上拉加载更多
- java基础--2.基本语法-1
- 手把手教你DIY一个春运迁徙图(一)
- Kibana using lots memory