Android上的SimpleDateFormat时区错误

我一直在试图隔离我的应用程序中的错误。 我成功制作了下面的“谜语”:

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上运行这个代码时,我得到了评论中的值(是的,真的)。 这种行为取决于特定的Java实现。

我的问题是:

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

问题1的答案请参阅BalusC的答案:

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

对问题2的回答请看wrygiel(我自己)的答案。

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

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

根据给定的parsing位置parsingdate/时间string。 例如,时间文本"07/10/96 4:5 PM, PDT"将被parsing为相当于Date(837039900000L)

默认情况下,parsing是宽松的:如果input的格式不是这个对象格式方法使用的格式,但仍然可以parsing为date,则parsing成功。 客户可以通过调用setLenient(false)来坚持严格遵守格式。

此parsing操作使用calendar生成Date 。 因此,根据子类实现, calendar'sdate时间字段和TimeZone值可能已被覆盖。 之前由setTimeZone调用设置的任何TimeZone值可能需要恢复以进一步操作。

请注意最后一段。 遗憾的是,这并不能解释何时会发生这种情况。 要解决您的特定问题,您需要在格式化操作之前明确设置所需的时区。

至于SimpleDateFormat本身的可变性,这是多年以来的事情。 你不应该创build和分配它的一个实例作为一个静态或类variables,但总是作为一个方法(threadlocal)variables。

这是由于Android 2.1(API 7)中的一个错误 。 看起来Android程序员在他们的Android 2.1实现中遗漏了一些没有logging的Java行为 (它被归类为不可修复的bug本身!)。

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

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

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

我试图通过运行相同的程序来比较s1和s2。 他们等于我。 在这里输入图像说明