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"
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"
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);
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.
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 )
To round up/down with Apache commons-lang you can use next methods:
DateUtils.ceiling(date, Calendar.HOUR)
DateUtils.truncate(date, Calendar.HOUR)
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
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))
I try not to use additional libraries if I can achieve this with plain Java:
new Date( ((new Date().getTime() + 500) / 1000) * 1000 )
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();
}
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.
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;
}
}
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);
}
//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