10

I've been trying to isolate a bug in my application. I succeeded in producing the following "riddle":

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

I get the values in comments when I run this code on Android API 7 (yes, really). This behavior depends on particular Java implementation.

My questions are:

  • Why s1 does not equal s2?
  • And more importantly, why s1 is incorrect? While s2 points to a proper point in time, s1 does not. There seems to be a bug in Android's SimpleDateFormat implementation.

ANSWER TO QUESTION 1: See the answer by BalusC:

  • [After using SimpleDateFormat#parse] any TimeZone value that has previously been set by a call to setTimeZone may need to be restored for further operations.

ANSWER TO QUESTION 2: See the answer by wrygiel (myself).

  • This is due to a bug in Android 2.1 (API 7).
wrygiel
  • 5,080
  • 3
  • 24
  • 29

4 Answers4

8

This is mentioned in javadoc of DateFormat#parse():

Parse a date/time string according to the given parse position. For example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date that is equivalent to Date(837039900000L).

By default, parsing is lenient: If the input is not in the form used by this object's format method but can still be parsed as a date, then the parse succeeds. Clients may insist on strict adherence to the format by calling setLenient(false).

This parsing operation uses the calendar to produce a Date. As a result, the calendar's date-time fields and the TimeZone value may have been overwritten, depending on subclass implementations. Any TimeZone value that has previously been set by a call to setTimeZone may need to be restored for further operations.

Note the last paragraph. It unfortunately doesn't explain when exactly this will occur. To fix your particular problem you need to explicitly set the desired timezone before the formatting operation.

As to the mutability of SimpleDateFormat itself, this is known for years. You should never create and assign an instance of it as a static or class variable, but always as a method (threadlocal) variable.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • God, this is beyond me... I get mutability and thread issues, but all this happens in a single thread. `Date` objects have proper timezones set. Why the formatter does not access them for itself? It doesn't matter if it outputs a value in a different timezone **as long as it is correct**, and `s1` **is not**. I can't see WHY this ISN'T a bug. – wrygiel May 16 '12 at 19:11
  • Why do you have 2 instances in the same thread? All with all, I agree you, `DateFormat` (and `Date`) are not the best of Java SE. That's why JodaTime is extolled. – BalusC May 16 '12 at 19:11
  • I had only one instance, but it produced an invalid value (s1). I added the second one to get a valid one (s2). – wrygiel May 16 '12 at 19:13
  • If I parsed s1 again, I would get a d2 which does not equal d. I can't see how the documentation you cited explains that. – wrygiel May 16 '12 at 19:36
  • @wrygiel - f1 is used twice, while f2 is used once. when you use f1 to _parse_ the initial date string, it _changes_ the TimeZone of f1. thus, f1 and f2 now have different TimeZones, hence the different output when you format d. – jtahlborn May 16 '12 at 20:25
  • @jtahlborn - you are right, but this doesn't answer my second question. The key issue was - why s1 is incorrect (it doesn't matter if s1 and s2 are in different timezones, but they are actually pointing to different times!). I already found the most probable answer - there is a bug in Android's implementation of SimpleDateFormat (see the links in my own answer). – wrygiel May 16 '12 at 20:29
7

This is due to a bug in Android 2.1 (API 7). It seems that Android programmers missed some undocumented Java behavior (which is classified as an unfixable bug itself!) in their implementation of Android 2.1.

wrygiel
  • 5,080
  • 3
  • 24
  • 29
  • You should have quoted Java's linked bug (it's gone now); see another permanent Java bug: stackoverflow.com/ **[JTextField render bug?](https://stackoverflow.com/q/48203021/8740349)** – Top-Master May 21 '22 at 08:12
0

Your question intrigued me so I went ahead and compiled your code. The result? As expected...

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

The two values are the same, are you using some concurrency? Maybe the variable gets changed on another thread right before the f2.format(d).

0

I tried to compare s1 and s2 by running the same program. they come equal to me. enter image description here

Sukesh Kumar
  • 133
  • 2
  • 12
  • I guess it depends on implementation. On Android API 7 you would get the same values as I did. I promise ;) – wrygiel May 16 '12 at 19:16