37

I would like an elegant way to round a java Date up or down to the nearest minute (or second, hour, day).

For example a date of "Wed Jan 25 10:36:34 GMT 2012" rounded up to the nearest minute would be "Wed Jan 25 10:37:00 GMT 2012"

darrenmc
  • 1,721
  • 1
  • 19
  • 29
  • 2
    JodaTime?(http://joda-time.sourceforge.net/) Also this may be useful: http://stackoverflow.com/a/266846/579580 – aviad Jan 25 '12 at 10:50
  • JodaTime does not provide this feature. Using Calendar to extract the field values and then subtracting/adding them felt too ugly. – darrenmc Jan 25 '12 at 11:08

11 Answers11

63

If you use Apache commons-lang, you can use DateUtils to round your dates:

Date now = new Date();
Date nearestMinute = DateUtils.round(now, Calendar.MINUTE);
Guido
  • 46,642
  • 28
  • 120
  • 174
30

The way to do it without 3rd-party libraries (may be not so elegant and not so flexible, though): add a half of a field (for a rounding by minutes - 30 seconds) and set this field and lower ones to zero.

Calendar calendar = ... // assume you already have it with a specified Date value

// 'add' cause changing larger fields if necessary
calendar.add( Calendar.SECOND, 30 ); 
calendar.set( Calendar.SECOND, 0 );
calendar.set( Calendar.MILLISECOND, 0 );

If a current value is less than 30 seconds, a minute value won't change on 'add'. Otherwise, it will be increased by 1. In any case, seconds and lower values are zeroed. So we have a rounding.

Wizart
  • 940
  • 5
  • 8
9

You can use Apache-commons' DateUtils.

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 )
Guillaume
  • 22,694
  • 14
  • 56
  • 70
7

To round up/down with Apache commons-lang you can use next methods:

  • To round up use DateUtils.ceiling(date, Calendar.HOUR)
  • To round down use DateUtils.truncate(date, Calendar.HOUR)
  • To round to nearest unit use DateUtils.round(date, Calendar.HOUR)

See examples:

    SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");

    String sDate1 = "11-05-2019 19:01:00";
    Date date1 = formatter.parse(sDate1);
    System.out.println(DateUtils.round(date1, Calendar.HOUR));    // Sat May 11 19:00:00 MSK 2019
    System.out.println(DateUtils.truncate(date1, Calendar.HOUR)); // Sat May 11 19:00:00 MSK 2019
    System.out.println(DateUtils.ceiling(date1, Calendar.HOUR));  // Sat May 11 20:00:00 MSK 2019

    String sDate2 = "11-05-2019 19:29:00";
    Date date2 = formatter.parse(sDate2);
    System.out.println(DateUtils.round(date2, Calendar.HOUR));    // Sat May 11 19:00:00 MSK 2019
    System.out.println(DateUtils.truncate(date2, Calendar.HOUR)); // Sat May 11 19:00:00 MSK 2019
    System.out.println(DateUtils.ceiling(date2, Calendar.HOUR));  // Sat May 11 20:00:00 MSK 2019

    String sDate3 = "11-05-2019 19:30:00";
    Date date3 = formatter.parse(sDate3);
    System.out.println(DateUtils.round(date3, Calendar.HOUR));    // Sat May 11 20:00:00 MSK 2019
    System.out.println(DateUtils.truncate(date3, Calendar.HOUR)); // Sat May 11 19:00:00 MSK 2019
    System.out.println(DateUtils.ceiling(date3, Calendar.HOUR));  // Sat May 11 20:00:00 MSK 2019

    String sDate4 = "11-05-2019 19:31:00";
    Date date4 = formatter.parse(sDate4);
    System.out.println(DateUtils.round(date4, Calendar.HOUR));    // Sat May 11 20:00:00 MSK 2019
    System.out.println(DateUtils.truncate(date4, Calendar.HOUR)); // Sat May 11 19:00:00 MSK 2019
    System.out.println(DateUtils.ceiling(date4, Calendar.HOUR));  // Sat May 11 20:00:00 MSK 2019

    String sDate5 = "11-05-2019 19:59:00";
    Date date5 = formatter.parse(sDate5);
    System.out.println(DateUtils.round(date5, Calendar.HOUR));    // Sat May 11 20:00:00 MSK 2019
    System.out.println(DateUtils.truncate(date5, Calendar.HOUR)); // Sat May 11 19:00:00 MSK 2019
    System.out.println(DateUtils.ceiling(date5, Calendar.HOUR));  // Sat May 11 20:00:00 MSK 2019
5

here is a Java8+ answer:

public static Instant roundHalfUp(Instant instant, TemporalUnit unit) {
    return instant.plus(unit.getDuration().dividedBy(2))
            .truncatedTo(unit);
}

To round a date to the minute, with date-> instant -> date conversions:

Date.from(roundHalfUp(date.toInstant(), ChronoUnit.MINUTES))
bernard paulus
  • 1,644
  • 1
  • 21
  • 33
4

I try not to use additional libraries if I can achieve this with plain Java:

 new Date( ((new Date().getTime() + 500) / 1000) * 1000 )
Anatolii Stepaniuk
  • 2,585
  • 1
  • 18
  • 24
  • 1
    @Andy897 it is rounding down (floor) if number of millis is less than 500 and rounds up (ceiling) number of millis is more then 500. in this example I showed rounding to seconds. Although I would suggest you'd better use Java 8 Time API for this – Anatolii Stepaniuk Nov 11 '17 at 08:46
4

Best solution is to use the DateUtils from Apache commons. However if you want to avoid importing them this would be the solution in Java. Not sure if this qualifies as "elegant solution" means though.

/** 
      Takes given date and returns date rounded to nearest  minute
*/
public Date roundToMin(Date d){
    Calendar date = new GregorianCalendar();
    date.setTime(d);
    int deltaMin = date.get(Calendar.SECOND)/30;

    date.set(Calendar.SECOND, 0);
    date.set(Calendar.MILLISECOND, 0);
    date.add(Calendar.MINUTE, deltaMin);

    return date.getTime();
}
Daniel Fath
  • 16,453
  • 7
  • 47
  • 82
1

If you need to round minutes you can do so by, int minutes = minutes - (minutes % n);

if want to round off minutes by 5, then n = 5.

Dhruv garg
  • 689
  • 7
  • 22
0

Adding the commons-lang jar just to round a date is not a good idea, I prefer this function :

public static Date round(Date d) {
    try {
        SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");
        return sdf.parse(sdf.format(d));
    } catch (ParseException ex) {
        //This exception will never be thrown, because sdf parses what it   formats
        return d;
    }
}
Lhoussin Ghanem
  • 179
  • 1
  • 8
0

In the following function "roundBy" one can round the date
optionally by second / minute / hour / day.
It may not be accurate, yet the idea is clear, hopefully

public static final long MILLISECONDS_IN_SECOND = (long)(1000);
public static final long MILLISECONDS_IN_MINUTE = (MILLISECONDS_IN_SECOND * 60);
public static final long MILLISECONDS_IN_HOUR = (MILLISECONDS_IN_MINUTE * 60);
public static final long MILLISECONDS_IN_DAY = (MILLISECONDS_IN_HOUR * 24);
public synchronized static Date roundBy(Date date, long UNIT) {
    long time = date.getTime();
    long timeOutOfUnit= time % UNIT;
    time -= timeOutOfUnit;
    if(timeOutOfUnit >= (UNIT / 2)) {
        time += UNIT;
    }
    return new Date(time);
}
0
   //How about if we represent the window to round to in Duration
   // like this
   Duration duration = Duration.of(14, ChronoUnit.MINUTES);


   // example of any time
   ZonedDateTime time = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
   long s = duration.getSeconds();
   long st = time.toEpochSecond();
   st = st - st%s;

   time = ZonedDateTime.ofInstant(Instant.ofEpochSecond(st), time.getZone());

   // this trims the nanos and round to secons