Win a copy of The Java Performance Companion this week in the Performance forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

DateFormat.format unexpected side effect

 
Jacob Anawalt
Ranch Hand
Posts: 64
Linux Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
While using a SimpleDateFormat and a couple of GregorianCalendar objects in what I thought was a simple piece of code, I came across something that was quite unexpected. When I would call DateFormat.format, one of my Calendar objects would get updated to reflect the Date passed into the function.

After a lot of unfruitful searching and testing I found that the affected Calendar object was the one I passed into DateFormat.setCalendar. If I didn't set the calendar or if I set it using a defensive copy then the program worked as I expected.

As far as I can tell this behavior is undocumented in the 1.6 Javadocs. DateFormat.setCalendar doesn't say if it makes a copy or not and DateFormat.format doesn't mention it will change the Calendar object it was given. I haven't tested but now I won't be surprised if DateFormat.parse also changes it's related Calendar object. I think DateFormat.setCalendar should have done the defensive copy.

Are there well-known patterns that use this side-effect on the Calendar object given to DateFormat.setCalendar? How about a list of gotchas that like Odi's Date and Time in Java that warns of this side-effect? I didn't find them and that makes me think I did something unusual.

Here's the test case:



And the output:
CalendarCloneTest wrote:
cal: 2010-10-27
cal : 2010-Oct-27 16:56 EDT
cal2: 2010-Oct-27 16:56 EDT (clone)
cal : 2010-Oct-27 16:56 EDT
cal2: 2010-Nov-03 00:56 EDT (post-add/set)
cal : 2010-Nov-03 00:56 EDT (post-cal2-add/set)
cal2: 2010-Nov-03 00:56 EDT
 
Bobby Smallman
Ranch Hand
Posts: 107
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
To my knowledge there are a few different ways this, for lack of a better word "linked cloning" comes about. I had not encountered it in exactly the same way you have, so it sparked my interest. Check out this link for a similar yet different issues to potentially help shed some light on the situation, I look forward to hearing what others on here say.

http://techvivek.wordpress.com/2010/07/31/calendar-clone-problem/
 
Campbell Ritchie
Sheriff
Pie
Posts: 49382
62
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think this question is too difficult for "beginning Java" so I shall move it.
 
Rob Spoor
Sheriff
Pie
Posts: 20546
57
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Unless the documentation specifies otherwise you should always assume the worst.
 
Kurt Van Etten
Ranch Hand
Posts: 98
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Bobby Smallman wrote:To my knowledge there are a few different ways this, for lack of a better word "linked cloning" comes about. I had not encountered it in exactly the same way you have, so it sparked my interest. Check out this link for a similar yet different issues to potentially help shed some light on the situation, I look forward to hearing what others on here say.

http://techvivek.wordpress.com/2010/07/31/calendar-clone-problem/


In that link, they refer to the weird behavior as a cloning problem, but the code is doing exactly the same thing that Jacob's example does. You can verify that it's not the cloning part that causes the behavior by just instantiating a separate, second Calendar object instead of using the clone function--you will get similar behavior. Although the API documentation doesn't spell it out, it seems pretty clear that the DateFormat.format() method is applying the date/time parameter value to its calendar as part of the formatting process.
 
Jacob Anawalt
Ranch Hand
Posts: 64
Linux Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I too thought my problem was with clone being a shallow and not a deep copy when I first ran into this. My actual program used a loop similar to the Calendar clone problem example on Vivek's Tech Blog but as my test case shows instead of getting the Calendar from the DateFormat object, I was setting my "baseCalendar" (cal) into my DateFormat object. In the end the effect is the same, the DateFormat and my "baseCalendar" are a reference to the same object being modified with each call to DateFormat.format.

Since I just got bit it currently feels like a bug that DateFormat.setCalendar doesn't itself make the defensive copy and perhaps Vivek will feel it is a bug that DateFormat.getCalendar doesn't appear to return a defensive copy. I recognize that others may be taking advantage of this side effect as a feature so the most I hope for is better education/documentation.

I agree, assuming the worst is safest. Being new to Java I was wondering if this side-effect was commonly used as a feature or listed somewhere as a gotcha.
 
Jacob Anawalt
Ranch Hand
Posts: 64
Linux Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I searched through the bug list and found a few that show similar mistakes or comments on how to use DateFormat related to get/setCalendar and parse/format. Here are a couple of notable ones with their problems, workarounds and the bug triage evaluation comments paraphrased. See the actual bug reports for exact details.

Bug 6609675: [Fmt-Da] DateFormat.parse() on a timezone changes its calendar's timezone

Problem:
DateFormat.parse() has an undocumented side-effect: calling it with a string that contains a timezone, different from one that was explicitly set, will overwrite the DateFormat's internal timezone with that of the string.

Further attempts to use the DateFormat for formatting will use the new timezone.

Workaround:
Use separate DateFormats for formatting and parsing.

Evaluation:
- The parse methods may overwrite the date-time fields and the TimeZone value of the embedded calendar (DateFormat.calendar).



Bug 6609452: [Fmt-Da] DateFormat.getCalendar().getTime() outputs wrong year

Problem:
Inputting DateFormat.calendar.getTime() into DateFormat.format gives the wrong results.

Workaround:
Use a different source for the Calendar object or make a new Date.

Evaluation:
The Calendar instance in a DateFormat is first used to calculate the base year for the 2-digit year handling. Please don't rely on the [ DateFormat ] Calendar fields.

 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic