【问题标题】:SimpleDateFormat timezone bug on AndroidAndroid 上的 SimpleDateFormat 时区错误
【发布时间】:2012-05-24 09:10:43
【问题描述】:

我一直在尝试隔离我的应用程序中的错误。我成功地产生了以下“谜语”:

SimpleDateFormat f1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
SimpleDateFormat f2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date d = f1.parse("2012-01-01T00:00:00+0700");
String s1 = f1.format(d); // 2011-12-31T18:00:00+0700
String s2 = f2.format(d); // 2011-12-31T18:00:00+0100

当我在 Android API 7 上运行此代码时,我得到了 cmets 中的值(是的,真的)。此行为取决于特定的 Java 实现。

我的问题是:

  • 为什么 s1 不等于 s2?
  • 更重要的是,为什么 s1 不正确?s2 指向正确的时间点,s1 却没有。 Android 的 SimpleDateFormat 实现中似乎存在错误。

问题 1 的答案:查看 BalusC 的答案:

  • [使用SimpleDateFormat#parse] 之前通过调用 setTimeZone 设置的任何 TimeZone 值可能需要恢复以进行进一步操作。

问题 2 的答案:请参阅 wrygiel(我自己)的答案。

  • 这是由于 Android 2.1 (API 7) 中的错误造成的。

【问题讨论】:

  • 我运行了你的代码。当我运行时,两个输出都是一样的
  • 我在 Android API 7 上运行。也许这很重要。我会更新描述。
  • 我也运行你的代码。 s1 和 s2 是相同的 - 问题出在您的“不可见”(对我们而言)代码中。

标签: java android


【解决方案1】:

这在DateFormat#parse()的javadoc中提到:

根据给定的解析位置解析日期/时间字符串。例如,时间文本"07/10/96 4:5 PM, PDT" 将被解析为与Date(837039900000L) 等效的日期。

默认情况下,解析是宽松的:如果输入不是该对象的格式方法使用的格式,但仍然可以解析为日期,则解析成功。客户可致电setLenient(false),要求严格遵守格式。

此解析操作使用calendar 生成Date。因此,calendar's 日期时间字段和TimeZone 值可能已被覆盖,具体取决于子类实现。之前通过调用setTimeZone 设置的任何TimeZone 值可能需要恢复以进行进一步操作。

注意最后一段。不幸的是,它并没有准确地解释 何时 这会发生。要解决您的特定问题,您需要在格式化操作之前明确设置所需的时区。

至于SimpleDateFormat 本身的可变性,这是众所周知的多年。您永远不应将其实例创建并分配为静态或类变量,而应始终作为方法(线程本地)变量。

【讨论】:

  • 上帝,这超出了我的范围......我遇到了可变性和线程问题,但所有这些都发生在一个线程中。 Date 对象设置了适当的时区。为什么格式化程序不自己访问它们?它是否在不同的时区输出值无关紧要只要它是正确的,而s1 不是。我看不出为什么这不是错误。
  • 为什么在同一个线程中有 2 个实例?总之,我同意你,DateFormat(和Date)并不是最好的 Java SE。这就是 JodaTime 受到赞誉的原因。
  • 我只有一个实例,但它产生了一个无效值 (s1)。我添加了第二个以获得有效的(s2)。
  • 如果我再次解析 s1,我会得到一个不等于 d 的 d2。我看不出你引用的文档是如何解释的。
  • @wrygiel - f1 使用两次,而 f2 使用一次。当您使用 f1 来解析初始日期字符串时,它会更改 f1 的 TimeZone。因此,f1 和 f2 现在有不同的时区,因此当您格式化 d 时输出不同。
【解决方案2】:

这是由于 Android 2.1 (API 7) 中的a bug。 Android 程序员似乎在他们的 Android 2.1 实现中错过了some undocumented Java behavior(这本身就是一个不可修复的错误!)。

【讨论】:

    【解决方案3】:

    你的问题引起了我的兴趣,所以我继续编译你的代码。结果?果然……

    2011-12-31T18:00:00+0100
    2011-12-31T18:00:00+0100
    

    这两个值是一样的,你是在使用一些并发吗?也许变量在f2.format(d) 之前的另一个线程上被更改。

    【讨论】:

    • 好吧,我不是。目前我的 Application#onCreate 方法中有这些语句。
    【解决方案4】:

    我尝试通过运行相同的程序来比较 s1 和 s2。他们和我一样。

    【讨论】:

    • 我猜这取决于实现。在 Android API 7 上,您将获得与我相同的值。我保证;)
    猜你喜欢
    • 1970-01-01
    • 2011-12-18
    • 2015-12-19
    • 2016-08-30
    • 1970-01-01
    • 2021-08-16
    • 2013-04-13
    • 1970-01-01
    相关资源
    最近更新 更多