SimpleDateFormat.parse导致基于Android版本的非常不同的值

时间:2017-02-01 19:32:03

标签: android simpledateformat

我一直在为此抨击我。我制作了一个小样本应用程序,以确保我没有看到任何东西,或者在稍后我没有抓到的时候没有操纵这些值。

问题在于,当我尝试使用日期格式解析字符串日期时,根据设备API级别,我得到两个非常不同的结果。

DateFormat utcFormat;
String utcDate = "2017-01-31 18:58:12.2334924Z";
utcFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSS'Z'");
utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
try{
    conversion.setText(utcFormat.parse(utcDate).toString());
}
catch (ParseException e){
    conversion.setText("exception encountered: " + e.getMessage());
}

以下是我的结果:

On Android 4.4.2 device: Tue Jan 31 14:37:06 EST 2017
On Android 6.0.1 device: Tue Jan 31 13:58:12 EST 2017

正如您所看到的,基于完全相同的输入,差异大约为40分钟。设备区域设置是相同的(虽然我也尝试过硬编码区域设置),设备上的设置时间相等。

我在这里做错了吗?

1 个答案:

答案 0 :(得分:2)

符号S的一般问题是: java.util.Datejava.text.SimpleDateFormat的精度最多只能达到毫秒。不支持更高的精度。因此,指定多于3个模式符号SSS是没有意义的。

此外,我尝试做了一些研究,发现了这个:

pattern symbol table of official javadoc指定" S" as" Millisecond"。这意味着,值为" 2334924"输入中点后面的字面解析为毫秒的绝对计数,导致大约39分钟。这解释了在Android v4.4上测试的第一个示例的解析时间。

然而,发布的javadoc似乎在这个细节上略显过时。如果你谷歌搜索source code,那么你会在第71行找到:

 <tr> <td>{@code S}</td> 
 <td>fractional seconds</td>      
 <td>(Number)</td>      
 <td>978</td> </tr>

但小数秒会导致对文本的完全不同的解释 &#34; 2334924&#34;,即233毫秒(加上忽略的更高精度部分)。这解释了您在Android v6上的第二个代码示例。我怀疑在两个Android版本之间的某个地方,谷歌决定在没有任何文档的情况下改变行为。我能找到的最好的东西似乎是issue 78859,这可能与行为的这种变化有关。

ICU4J似乎越来越多地集成到较新的Android版本中,也声明了符号&#34; S&#34;作为小数秒。

解决方法和解决方案:

避免使用3个以上的图案符号S.而是使用(忽略更高精度的部分):

String input = "2017-01-31 18:58:12.2334924Z";
int dot = input.indexOf("."); 
String trimmed = input.substring(0, dot + 4) + "Z"; // 2017-01-31 18:58:12.233Z
DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS'Z'");
utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
java.util.Date d = utcFormat.parse(trimmed);