Issue Details (XML | Word | Printable)

Key: LANG-59
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Unassigned
Reporter: Li Zhang
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
Commons Lang

[lang] DateUtils.truncate method is buggy when dealing with DST switching hours

Created: 26/Oct/05 07:22 AM   Updated: 06/Feb/07 11:47 PM
Return to search
Component/s: None
Affects Version/s: 2.1
Fix Version/s: 2.2

Time Tracking:
Not Specified

File Attachments:
  Size
Text File Licensed for inclusion in ASF works lang_issue_59.txt 2006-07-16 05:19 AM Niall Pemberton 6 kB
Environment:
Operating System: Windows XP
Platform: Other

Bugzilla Id: 37243
Resolution Date: 21/Jul/06 05:15 AM


 Description  « Hide
Try to truncate 2004-10-31 01:00:00 MDT by hour and you'll actually get 2004-10-
31 01:00:00 MST, which is one hour after the input hour.

// truncate 2004-10-31 01:00:00 MDT
Date oct31_01MDT = new Date(1099206000000L);
Date result = DateUtils.truncate(oct31_01MDT, Calendar.HOUR_OF_DAY);
assertEquals(oct31_01MDT, result);



 All   Comments   Work Log   Change History   Subversion Commits      Sort Order: Ascending order - Click to sort in descending order
Henri Yandell added a comment - 27/Jun/06 07:28 AM
Definitely a reproducable bug - not sure how to fix it though.

Henri Yandell added a comment - 04/Jul/06 02:19 AM
Most frustatingly, sometimes the test passes and sometimes it fails. Possibly based on time of day the test is run.

Li Zhang added a comment - 05/Jul/06 01:43 AM
I did a little hack and found this bug could be fixed with the following modification on DateUtils.modify method:
private static void modify(Calendar val, int field, boolean round) {
...
if (!offsetSet) { int min = val.getActualMinimum(fields[i][0]); int max = val.getActualMaximum(fields[i][0]); //Calculate the offset from the minimum allowed value offset = val.get(fields[i][0]) - min; //Set roundUp if this is more than half way between the minimum and maximum roundUp = offset > ((max - min) / 2); }
//We need to remove this field - Do nothing if there is no change
if (offset != 0) { <--- add the check val.set(fields[i][0], val.get(fields[i][0]) - offset); }
}
throw new IllegalArgumentException("The field " + field + " is not supported");
}

Calendar.set method resets some fields (e.g., DST_OFFSET) even if the new value is the same as the old value. We just need to add a check before setting the new value to a field. If there is no change on this field, do not call Calendar.set method.


Henri Yandell added a comment - 05/Jul/06 01:58 AM
Many thanks - any thoughts on why the test case only fails some of the time?

Li Zhang added a comment - 05/Jul/06 02:01 AM
Forget my previous post. The fix is broken. The problem is sometimes when you call Calendar.set method the DST_OFFSET field is reset to 0.

Niall Pemberton added a comment - 16/Jul/06 05:19 AM
The problem seems to be with java.util.Calendar - as soon as it re-calculates the milliseconds it adjusts the time - even if you set a field without actually changing the value(i.e. set it to the same value) the same thing happens - it adds an hour to the time (see test case which demonstrates this).

I'm attaching a pragmatic, but not very elegant solution that works for truncating (and rounding down) - rather than using the Calendar methods to adjust milliseconds, seconds and minutes it adjusts the Date's millisecond value directly. Its only fields down to the "hour" level that affect the date - so truncating milliseconds, seconds and minutes should work fine since they will still be the same date. Combined with Li Zhang's suggestion of only setting fields which have changed - this seems to work.


Henri Yandell added a comment - 16/Jul/06 05:35 AM
Very, very cool. Patch applied locally and passes tests. Will run the tests a few times through the day tomorrow as they tend to pass in the evening (I think) anyway. If it survives tomorrow, I'll apply the fix.

Henri Yandell added a comment - 21/Jul/06 05:15 AM
Niall's fix seems to be working Passed tests in morning and evening which seemed to have some impact on the bug.

Please reopen if it's not working for you, Li.


Henri Yandell added a comment - 21/Jul/06 05:46 AM
Now I've actually done the commit. Doh.

svn ci -m "Adding Niall's fix for LANG-59 - an edge case in date truncation - and his enhancement for the unit test that was there. " src/
Sending src/java/org/apache/commons/lang/time/DateUtils.java
Sending src/test/org/apache/commons/lang/time/DateUtilsTest.java
Transmitting file data ..
Committed revision 424192.

Should be in tonight's nightly build:

http://people.apache.org/repository/commons-lang/jars/commons-lang-20060721.jar