【问题标题】:Get wrong Date from parsing time string by SimpleDateFormat. (1 hour offset) [Android/Java]通过 SimpleDateFormat 从解析时间字符串中获取错误的日期。 (1 小时偏移)[Android/Java]
【发布时间】:2015-04-29 16:56:17
【问题描述】:

首先,我想明确一点,这不是夏令时问题。

其次,经过努力,似乎与SimpleDateFormat中使用的locale有关。

第三,它似乎只发生在 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: 太平洋标准时间 2 月 26 日 19:42:42

02-26 19:42:42.866 I/DEBUG: EN_str: 太平洋标准时间 2 月 26 日 19:42:42

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

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

更新: 它似乎只发生在 Android 5.0 设备上。 其他环境好像没问题。

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

【问题讨论】:

  • 还没有修复?我在德国,2015 年 4 月 17 日 09:26。调用字符串 currentDateandTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime());返回 2015-04-16 16:22:49(错误的日期和错误的时间)。

标签: java android timezone locale simpledateformat


【解决方案1】:

来自 Android 问题 Issue 158265

谷歌工程师回复如下。

Nexus 5 似乎无法更新 RTC 时钟硬件。当用户(或操作系统)更改时钟时,它不会永久保存在设备硬件上。下次设备重新启动时,它会从 RTC 硬件读取值并将其设置为系统时钟。就我而言,我尝试过的两台设备的 RTC 设置为 1971。

系统时钟(用户看到的)最初是从 RTC 设置的,但它是独立的。如果用户已将设备设置为从网络源同步系统时钟,那么当设备完成启动时,系统时钟将被正确设置。如果没有能力写回它,RTC 仍然是错误的。

不幸的是,用于解析区域信息(如 PST)的信息在启动期间在 zygote 进程中被缓存,而时钟仍然错误。就我而言,它正在查看 1971 年的时区名称,但随后使用今天的偏移信息。这意味着我们错误地选择了 Dawson_Creek 作为 PST 的代理,但 Dawson_Creek 今天的偏移量实际上是 MST/MDT 的偏移量。

看到某些语言环境问题而不是其他语言环境的原因是 zygote 缓存在启动后最多包含 3 个条目:

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

使用 ENGLISH (en) 被识别为与 US (en_US) 不同的语言环境 所以它不使用启动过程中缓存的数据,所以当前 (正确)使用了系统时钟时间。

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

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

使用与默认值不同的 Locale 进行解析的结果是正确的,因为它生成的时区数据的时间已经与网络时间更正/同步。

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

【讨论】:

    【解决方案2】:

    我认为错误可能来自 Logger。它与语言环境无关。

        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:IST 2 月 27 日 12:18:26

    US_str:IST 2 月 27 日 12:18:26

    EN_str:IST 2 月 27 日 12:18:26

    EN_str:IST 2 月 27 日 12:18:26

    希望对你有所帮助。

    【讨论】:

    • 我尝试了您的代码,但在我的设备中得到了相同的结果。
    • 您能帮忙使用 PST/PDT 时区吗?我认为这个问题与时区和语言环境有关。
    猜你喜欢
    • 1970-01-01
    • 2014-09-07
    • 2013-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-29
    • 2015-10-27
    相关资源
    最近更新 更多