1.14. Rounding Date Objects

Problem

You need to round a date to the nearest second, minute, hour, day, month, or year.

Solution

Use DateUtils to round Date objects to the nearest Calendar field. DateUtils.round() can round to almost every Calendar field, including Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR, Calendar.DAY_OF_MONTH, Calendar.MONTH, and Calendar.YEAR. The following example demonstrates the use of DateUtils.round( ):

import org.apache.commons.lang.time.FastDateFormat;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;

FastDateFormat dtFormat = DateFormatUtils.ISO_DATETIME_FORMAT;

Date now = new Date( );
Date nearestHour = DateUtils.round( now, Calendar.HOUR );
Date nearestDay = DateUtils.round( now, Calendar.DAY_OF_MONTH );
Date nearestYear = DateUtils.round( now, Calendar.YEAR );

System.out.println( "Now: " + dtFormat.format( now ) );
System.out.println( "Nearest Hour: " + dtFormat.format( nearestHour ) );
System.out.println( "Nearest Day: " + dtFormat.format( nearestDay ) );
System.out.println( "Nearest Year: " + dtFormat.format( nearestYear ) );

This example creates an object representing the current time and rounds this date to the nearest hour, day, and year. Assuming that the current date is March 28, 2004, and the current time is 1:48 P.M., this program creates the following output using the FastDateFormat class from the previous recipe:

Now: 2004-03-28T13:48:12
Nearest Hour: 2004-03-28T14:00:00
Nearest Day: 2004-03-29T00:00:00
Nearest Year: 2004-01-01T00:00:00

Discussion

If you are creating a system to record the time of an event, and you are not certain exactly when that event happened, it is appropriate to round that date and time to an approximate value. Are you certain that you woke up at 9:02 A.M., 23 seconds, and 879 milliseconds? Or, is it more likely that you remember that you woke up around 9 A.M.? It would be appropriate to round this time to the Calendar.MINUTE or Calendar.HOUR field at the very least—recording a general time, such as “around 9 A.M.” In the following example, DateUtils.round( ) calculates an approximate time:

// Rounding to the nearest hour
Date wokeUp = new Date( );
Date wokeUpAround = DateUtils.round( now, Calendar.HOUR );

If your wokeUp Date object is 1:31 P.M., then wokeUpAround will be equal to 2:00 P.M. But, if you woke up at 1:15 P.M., your wokeUpAround object would then be rounded down to 1:00 P.M. When you round or truncate to a field, all of the date fields less significant than the specified field are set to zero. In this example, rounding to an hour causes the minutes, seconds, and milliseconds to be set to zero. Rounding a Date to a Calendar.YEAR sets the day of the year to one and the time to the first instance of the nearest year:

Date now = new Date( )
Date nearestYear = DateUtils.round( now, Calendar.YEAR );

This previous code rounds to the nearest year, and if now is 15 May 2004, the resulting Date will correspond to the first instance of 2004. Alternatively, if now is 15 July 2004, the resulting Date will be the first instance of 2005.

DateUtils.round( ) works with the following field values, listed in order of significance:

  • Calendar.MILLISECOND

  • Calendar.SECOND

  • Calendar.MINUTE

  • Calendar.HOUR_OF_DAY and Calendar.HOUR

  • Calendar.DATE, Calendar.DAY_OF_MONTH, and Calendar.AM_PM

  • Calendar.MONTH

  • DateUtils.SEMI_MONTH

  • Calendar.YEAR

  • Calendar.ERA

DateUtils introduces a DateUtils.SEMI_MONTH field, which will cause dates to be rounded to the middle or beginning of a month. In DateUtils, the middle of the month is defined as the 15th day of the month with the second half of the month starting at midnight on the 16th day of the month:

Calendar cal = Calendar.getInstance( );
cal.set( 2004, Calendar.MARCH, 5, 10, 2, 2 );

System.out.println( DateUtils.round( cal.getTime( ) , 
DateUtils.SEMI_MONTH ) );

This code will print out Mon Mar 01 00:00:00 CST 2004 as the 5th of March and is closer to the beginning of the month than it is to the middle of the month. If the Calendar object was March, 14th, 2004, and it had been rounded to a DateUtils.SEMI_MONTH, the rounded date would have been set to midnight on March 16th. One would think that the middle of March is the 15th? Isn’t that date the famous Ides of March—the date on which Brutus betrayed Caesar? According to DateUtils, the first half of the month ends at 11:59 P.M. on the 15th of the month; the DateUtils.round( ) method returns the first instant of the beginning of the second half of March: March 16 12:00:00.000 A.M.

See Also

The more you work with Java’s Date and Calendar object, the more you will curse the J2SE. If your frustration is boiling over, take a look at Joda. Joda contains an entire package devoted to date, time, and duration formatting, and it is not based on the Date or Calendar classes. For more information about Joda, take a look at the Joda project page at: http://www.joda.org/.

Get Jakarta Commons Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.