Java дата округления
Я хотел бы элегантный способ округлить дату Java вверх или вниз до ближайшей минуты (или секунды, час, день).
Например, дата "ср 25 января 10:36:34 GMT 2012", округленная до ближайшей минуты, будет "ср 25 января 10:37:00 GMT 2012"
7 ответов
Если вы используете Apache commons-lang, вы можете использовать DateUtils для округления дат:
Date now = new Date();
Date nearestMinute = DateUtils.round(now, Calendar.MINUTE);
Способ сделать это без сторонних библиотек (может быть, не такой элегантный и не такой гибкий): добавить половину поля (для округления по минутам - 30 секунд) и установить это поле и нижние в ноль.
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 );
Если текущее значение меньше 30 секунд, минутное значение не изменится при добавлении. В противном случае он будет увеличен на 1. В любом случае, секунды и более низкие значения обнуляются. Итак, у нас есть округление.
Вы можете использовать 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 )
Для округления вверх / вниз с Apache commons-lang вы можете использовать следующие методы:
- Чтобы округлить использование
DateUtils.ceiling(date, Calendar.HOUR)
- Чтобы округлить, используйте
DateUtils.truncate(date, Calendar.HOUR)
- Чтобы округлить до ближайшей единицы, используйте
DateUtils.round(date, Calendar.HOUR)
См. Примеры:
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
Вот ответ Java8+:
public static Instant roundHalfUp(Instant instant, TemporalUnit unit) {
return instant.plus(unit.getDuration().dividedBy(2))
.truncatedTo(unit);
}
Чтобы округлить дату до минуты, с преобразованием даты-> мгновенно -> даты:
Date.from(roundHalfUp(date.toInstant(), ChronoUnit.MINUTES))
Я стараюсь не использовать дополнительные библиотеки, если я могу добиться этого с простой Java:
new Date( ((new Date().getTime() + 500) / 1000) * 1000 )
Лучшее решение - использовать DateUtils от Apache Commons. Однако, если вы хотите избежать их импорта, это будет решением в Java. Не уверен, что это означает "элегантное решение".
/**
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();
}
Если вам нужно округлить минуты, вы можете сделать это с помощью int minutes = minutes - (minutes % n);
если хотите округлить минуты на 5, тогда n = 5.
Добавлять банку commons-lang просто для округления даты не очень хорошая идея, я предпочитаю эту функцию:
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;
}
}
//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
В следующей функции "roundBy" можно округлить дату
опционально по секундам / минутам / часам / дням.
Это может быть неточным, но идея ясна, надеюсь
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);
}