通过 SimpleDateFormat 解析时间字符串得到错误的日期。 (1 小时偏移量)[Android/Java]

Get wrong Date from parsing time string by SimpleDateFormat. (1 hour offset) [Android/Java]

首先声明一下,不是夏令时问题

其次,经过努力,似乎与SimpleDateFormat中使用的语言环境有关。

第三,它似乎只发生在 PST/PDT 时区。 UTC 没问题。


这是测试代码。

使用美国和英语区域设置来解析相同的日期。

    try {
        Date date = new Date();
        SimpleDateFormat US_format = new SimpleDateFormat("MMM d HH:mm:ss z", Locale.US);
        SimpleDateFormat EN_format = new SimpleDateFormat("MMM d HH:mm:ss z", Locale.ENGLISH);

        US_format.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); //Set PST Timezone
        String US_str =  US_format.format(date);
        Log.i("DEBUG", "US_str: " + US_str);
        Log.i("DEBUG", "US_str: " + US_format.format(US_format.parse(US_str)));

        EN_format.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); //Set PST Timezone
        String EN_str =  EN_format.format(date);
        Log.i("DEBUG", "EN_str: " + EN_str);
        Log.i("DEBUG", "EN_str: " + EN_format.format(EN_format.parse(EN_str)));
    } catch (ParseException e) {
        Log.i("DEBUG", "Parsing Error");
    }

结果是

02-26 19:42:42.863 I/DEBUG﹕ US_str: Feb 26 19:42:42 PST

02-26 19:42:42.865 I/DEBUG﹕ US_str: Feb 26 18:42:42 PST

02-26 19:42:42.865 I/DEBUG﹕ EN_str: Feb 26 19:42:42 PST

02-26 19:42:42.866 I/DEBUG﹕ EN_str: Feb 26 19:42:42 PST

这是一个错误吗? 为什么 Locate.US 有一个小时的差异?

====================================

更新: 它似乎只发生在 Android 5.0 设备上。 其他环境似乎还可以。

在 Android 问题跟踪器上发布了错误。 (问题158265

我认为错误可能来自 Logger.It 与区域设置无关。

    Date date = new Date();
    SimpleDateFormat US_format = new SimpleDateFormat("MMM d HH:mm:ss z", Locale.US);
    SimpleDateFormat EN_format = new SimpleDateFormat("MMM d HH:mm:ss z", Locale.ENGLISH);

    String US_str =  US_format.format(date);
    System.out.println( "US_str: " + US_str);
    System.out.println( "US_str: " + US_format.format(US_format.parse(US_str)));

    String EN_str =  EN_format.format(date);
    System.out.println( "EN_str: " + EN_str);
    System.out.println( "EN_str: " + EN_format.format(EN_format.parse(EN_str)));

这是在我的电脑上获得的输出:

US_str:2 月 27 日 12:18:26 IST[​​=11=]

US_str:2 月 27 日 12:18:26 IST[​​=11=]

EN_str:2 月 27 日 12:18:26 IST[​​=11=]

EN_str:2 月 27 日 12:18:26 IST[​​=11=]

希望对你有帮助。

来自 Android 期 Issue 158265.

Google工程师的回答如下。

The Nexus 5 appears to not be able to update the RTC clock hardware. When the user (or the OS) changes the clock it is not persisted to the device hardware permanently. The next time the device reboots it reads the value from the RTC hardware and sets it into the system clock. In my case, two devices I tried had the RTC set to 1971.

The system clock (what the user sees) is initially set from the RTC but is independent. If the user has set the device to sync the system clock from a network source then by the time the device has finished booting the system clock will be set correctly. Without the ability to write back to it the RTC will still be wrong.

Unfortunately, the information used for parsing zone information like PST is cached during boot in the zygote process while the clock is still wrong. In my case it is looking at the timezone names as they were in 1971, but then using the offset information for today. This means that we incorrectly select Dawson_Creek as a proxy for PST, but the offset for Dawson_Creek today is actually that for MST/MDT.

The reason of seeing issues with some locales and not others is that the zygote cache contains at most 3 entries after boot:

1) Locale.ROOT 2) Locale.US 3)

Using ENGLISH (en) is recognized as different locale than US (en_US) so it does not use the data cached during boot, and so the current (correct) system clock time is used.

简而言之,此问题应该只发生在具有 BAD RTC 硬件的 Android 设备上。

zygote 进程在 BAD 时间的启动序列开始时生成时区缓存。所以用默认的Locale.US解析时区是错误的。

使用不同于默认的Locale解析的结果是正确的,因为它生成的时区数据的时间已经corrected/synced网络时间。

为避免此问题,请使用默认区域以外的区域设置来解析时区。