Учитывая сегодняшнее время, например. 14:24, как мне округлить до 14:30?
Точно так же, если время было 14:17, как мне округлить его до 14:15?
Учитывая сегодняшнее время, например. 14:24, как мне округлить до 14:30?
Точно так же, если время было 14:17, как мне округлить его до 14:15?
Вам нужно будет использовать модуль, чтобы усечь четверть часа:
Date whateverDateYouWant = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(whateverDateYouWant);
int unroundedMinutes = calendar.get(Calendar.MINUTE);
int mod = unroundedMinutes % 15;
calendar.add(Calendar.MINUTE, mod < 8 ? -mod : (15-mod));
Как указывает EJP, это тоже нормально (замена последней строки действительна, только если календарь мягкий):
calendar.set(Calendar.MINUTE, unroundedMinutes + mod);
Если вы хотите быть точным, вам также придется обрезать меньшие поля:
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Вы также можете использовать DateUtils.truncate() с Apache Commons/Lang на сделай это:
calendar = DateUtils.truncate(calendar, Calendar.MINUTE);
10:60
- это ужасно, даже если я знаю, что класс календаря достаточно умен, чтобы превратить его в 11:00
- person Sean Patrick Floyd; 24.08.2010
Если вы просто хотите округлить, это более удобочитаемая версия с использованием Java Time API:
LocalDateTime time = LocalDateTime.now();
LocalDateTime lastQuarter = time.truncatedTo(ChronoUnit.HOURS)
.plusMinutes(15 * (time.getMinute() / 15));
выход:
2016-11-04T10:58:10.228
2016-11-04T10:45:00
LocalDateTime
— это неправильный класс для реальных моментов, для точки на временной шкале. В отсутствие какой-либо концепции зоны/смещения они неопределенны. Используйте ту же логику, но с ZonedDateTime.now()
.
- person Basil Bourque; 18.03.2018
Закомментированная реализация для Java 8. Принимает произвольные единицы округления и приращения:
public static ZonedDateTime round(ZonedDateTime input, TemporalField roundTo, int roundIncrement) {
/* Extract the field being rounded. */
int field = input.get(roundTo);
/* Distance from previous floor. */
int r = field % roundIncrement;
/* Find floor and ceiling. Truncate values to base unit of field. */
ZonedDateTime ceiling =
input.plus(roundIncrement - r, roundTo.getBaseUnit())
.truncatedTo(roundTo.getBaseUnit());
ZonedDateTime floor =
input.plus(-r, roundTo.getBaseUnit())
.truncatedTo(roundTo.getBaseUnit());
/*
* Do a half-up rounding.
*
* If (input - floor) < (ceiling - input)
* (i.e. floor is closer to input than ceiling)
* then return floor, otherwise return ceiling.
*/
return Duration.between(floor, input).compareTo(Duration.between(input, ceiling)) < 0 ? floor : ceiling;
}
Источник: сам
return r < roundIncrement/2 ? floor : ceiling
, где roundIncrement/2
— порог, т.е. половина
- person hc_dev; 09.04.2020
Все просто, находим количество четвертей с 1970 года как двойное, округляем и умножаем на 15 минут:
long timeMs = System.System.currentTimeMillis();
long roundedtimeMs = Math.round( (double)( (double)timeMs/(double)(15*60*1000) ) ) * (15*60*1000) );
Установите свой объект даты или календаря с этим.
long timeMs = System.currentTimeMillis();
long roundedtimeMs = Math.round( (double)timeMs/(15*60*1000) ) * (15*60*1000);
- person jgrocha; 25.04.2017
С ответом выше вы получите весь интересный код для обработки переполнения часов, дней и т. д.
Я бы использовал время в мс с эпохи.
добавить 7,5 минут или 7,5x60x1000 = 450000
и обрезать до кратного 900000
new Date(900000 * ((date.getTime() + 450000) / 900000))
Это работает, потому что время начала отсчета мс равно 00:00:00. А поскольку все часовые пояса в мире меняются с шагом в 15 минут, это не влияет на округление до четверти.
(К сожалению, у меня было слишком много 0 и я забыл некоторые важные скобки: еще слишком рано)
Замечательный пост, спасибо большое ребята! Это было именно то, что мне было нужно :)
Вот мой код, основанный на моей работе.
Мой вариант использования: "Поскольку сейчас 11:47, я хочу установить две даты, символизирующие текущий 5-минутный кадр: 11:45 и 11:50"
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
int modulo = calendar.get(Calendar.MINUTE) % 5;
if(modulo > 0) {
calendar.add(Calendar.MINUTE, -modulo);
}
myObject.setStartDate(calendar.getTime());
calendar.add(Calendar.MINUTE, 5);
myObject.setDueDate(calendar.getTime());
Вы можете использовать этот простой код...
int mode = min % 15;
if (mode > 15 / 2) {
min = 15 - mode;
} else {
min = 0 - mode;
}
cal.add(Calendar.MINUTE, min);
min
, cal
) и объяснения.
- person hc_dev; 09.04.2020
Еще один альтернативный подход с использованием java Instant API.
Instant instant = Instant.now();
int intervalInMinutes = 10;
instant.truncatedTo(ChronoUnit.MINUTES).minus(instant.atZone(ZoneId.of("UTC")).getMinute() % (1* intervalInMinutes),ChronoUnit.MINUTES);
Я рекомендую вам сделать это, используя современную дату и время. API*:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Change it to the applicable ZoneId e.g. ZoneId.of("Asia/Kolkata")
ZoneId zoneId = ZoneId.systemDefault();
Stream.of(
"10:00",
"10:05",
"10:10",
"10:15",
"10:20",
"10:25",
"10:30"
).forEach(t -> System.out.println(roundToNearestQuarter(t, zoneId)));
}
static ZonedDateTime roundToNearestQuarter(String strTime, ZoneId zoneId) {
LocalTime time = LocalTime.parse(strTime);
return LocalDate.now()
.atTime(time)
.atZone(zoneId)
.truncatedTo(ChronoUnit.HOURS)
.plusMinutes(15 * Math.round(time.getMinute() / 15.0));
}
}
Вывод:
2021-04-02T10:00+01:00[Europe/London]
2021-04-02T10:00+01:00[Europe/London]
2021-04-02T10:15+01:00[Europe/London]
2021-04-02T10:15+01:00[Europe/London]
2021-04-02T10:15+01:00[Europe/London]
2021-04-02T10:30+01:00[Europe/London]
2021-04-02T10:30+01:00[Europe/London]
Если вам нужно только время, используйте ZonedDateTime#toLocalTime
чтобы получить LocalTime
из полученных ZonedDateTime
.
Узнайте больше о современном API даты и времени из Trail: Date Time< /а>сильный>.
* java.util
API даты и времени и их API форматирования SimpleDateFormat
устарели и подвержены ошибкам. Рекомендуется полностью отказаться от их использования и перейти на современный API даты и времени. По какой-либо причине, если вам нужно придерживаться Java 6 или Java 7, вы можете использовать ThreeTen-Backport, который переносит большую часть функций java.time на Java 6 и 7. Если вы работаете над проектом Android и вашим уровнем Android API по-прежнему не совместим с Java-8, проверьте Java 8+ API, доступные через дешугаринг и Как использовать ThreeTenABP в проекте Android.
Возможно, вы можете использовать служебную библиотеку для управления датами, например, здесь у вас есть круглый метод, который может быть вам полезен:
Вот пример в коде:
FastDateFormat formatter = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT;
Date now = new Date();
System.out.println("now = " + formatter.format(now));
// Get nearest second
Date nearestSecond = DateUtils.round(now, Calendar.SECOND);
System.out.println("nearestSecond = " + formatter.format(nearestSecond));
// Get nearest minute
Date nearestMinute = DateUtils.round(now, Calendar.MINUTE);
System.out.println("nearestMinute = " + formatter.format(nearestMinute));
// Get nearest hour
Date nearestHour = DateUtils.round(now, Calendar.HOUR);
System.out.println("nearestHour = " + formatter.format(nearestHour));
Если вам нужно округлить время до ближайшего произвольного уровня, указанного как Duration
:
static long truncateTo(long timeEpochMillis, Duration d) {
long x = timeEpochMillis / d.toMillis();
return x * d.toMillis();
}
если у вас есть минуты, вы можете округлить их с помощью следующей функции:int minutes = i % 15 < 8 ? i / 15 * 15 : (i / 15 + 1) * 15;
Используя некоторый код, который я нашел в Stackoverflow, я создал следующий код. Он будет выводить за каждую минуту квартал, до которого он будет округлен.
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
DateTimeFormatter Datum_Format = DateTimeFormatter.ofPattern("HH:mm");
LocalDateTime time = LocalDateTime.now();
for(int i=0; i<=59; i++) {
time = time.withMinute(i);
int Minute = time.getMinute();
int Quarter = 15 * (int) Math.round(Minute / 15);
if (Quarter == 60) {
Time2 = time.plusHours(1);
Time2 = Time2.withMinute(0);
LOG.info (Datum_Format.format(time) + "," + Datum_Format.format(Time2));
}
else {
Time2 = time;
Time2 = Time2.withMinute(Quarter);
LOG.info (Datum_Format.format(time) + "," + Datum_Format.format(Time2));
}
}
Поскольку я вывожу код на консоль, вам придется заменить LOG.info чем-то вроде System.out.println.
Результат:
2016-08-16 15:14:31 ИНФО 15:05,15:00
2016-08-16 15:14:31 ИНФО 15:06,15:00
2016-08-16 15:14 :31 ИНФО 15:07,15:00
2016-08-16 15:14:31 ИНФО 15:08,15:15
2016-08-16 15:14:31 ИНФО 15:09,15 :15
2016-08-16 15:14:31 ИНФОРМАЦИЯ 15:10,15:15
Используйте следующие функции, чтобы округлить минуты до последнего квартала getRecentQuater():Date
, getSysDate_LastQuarterMins("dd.MM.yyyy HH:mm:ss"):String
: Преобразование LocalDateTime to Date
public static Date getRecentQuater() {
LocalDateTime time = LocalDateTime.now();
LocalDateTime lastQuarter = time.truncatedTo(ChronoUnit.HOURS).plusMinutes(getLastQuarterValue(time.getMinute()));
System.out.println("lastQuarter LocalDateTime: " + lastQuarter);
Date date = Date.from(lastQuarter.atZone(ZoneId.systemDefault()).toInstant());
System.out.println("lastQuarter Date: " + lastQuarter);
return date;
}
public static String getSysDate_LastQuarterMins(String dateFormat) {
Date date = getRecentQuater();
SimpleDateFormat ft = new SimpleDateFormat (dateFormat);
String sysDate_RoundMin = ft.format(date);
System.out.println("getSysDate_LastQuarterMins() LocalDateTime : "+sysDate_RoundMin);
return sysDate_RoundMin;
}
getSysDate_LastQuarterMins() : Mon Jan 20 17:30:00 CET 2020
public static Date getSysDate_LastQuarterMins() {
Calendar cal = Calendar.getInstance();
cal.setTime( new Date(System.currentTimeMillis()) );
int min = cal.get(Calendar.MINUTE);
cal.set(Calendar.MINUTE, getLastQuarterValue(min));
cal.set(Calendar.SECOND, 00);
Date lastQuarter = cal.getTime();
System.out.println("getSysDate_LastQuarterMins() Calendar : "+lastQuarter);
return lastQuarter;
}
Вы можете найти значение LastQuarter Value Round из следующих функций, снабженных некоторыми выходными данными при вызове функции diaplayLastQuarter_RoundValue(min)
:
Min: 10, LastQuarter: 0, Round: 15
Min: 24, LastQuarter: 15, Round: 30
Min: 36, LastQuarter: 30, Round: 30
Min: 37, LastQuarter: 30, Round: 30
Min: 38, LastQuarter: 30, Round: 45
Min: 39, LastQuarter: 30, Round: 45
Min: 44, LastQuarter: 30, Round: 45
Min: 57, LastQuarter: 45, Round: 00 [57, 07:45:00, 08:00:00]
public static void diaplayLastQuarter_RoundValue(int minutes) {
System.out.format("Min: %2d, LastQuarter: %2d, Round: %2d\n",
minutes, getLastQuarterValue(minutes), getRoundValue(minutes));
}
public static int getLastQuarterValue(int minutes) {
int min = 15 * (minutes / 15);
//System.out.println("Min: "+minutes+", getLastQuarterValue : "+ min);
return min;
}
public static int getRoundValue(int minutes) {
getLastQuarterValue(minutes);
int minRound = (int) (Math.round(minutes / 15.0) * 15.0);
//System.out.println("Min: "+minutes+", getRoundValue : "+minRound);
return minRound;
}
Если кому-то интересно получить ближайший (вверх или вниз) интервал пять или пятнадцать, я сделал функцию, используя модуль, который выполняет эту работу.
public LocalTime roundToTheNearestInterval(LocalTime original, Integer measurementInterval) {
LocalTime nearest;
int mod;
switch (measurementInterval) {
case 5:
mod = original.getMinute() % 5;
nearest = mod >= 3 ?
original.truncatedTo(ChronoUnit.HOURS)
.plusMinutes((long) 5 * (original.getMinute() / 5) + 5) :
original.truncatedTo(ChronoUnit.HOURS)
.plusMinutes((long) 5 * (original.getMinute() / 5));
break;
case 15:
mod = original.getMinute() % 15;
nearest = mod >= 8 ?
original.truncatedTo(ChronoUnit.HOURS)
.plusMinutes((long) 15 * (original.getMinute() / 15) + 15) :
original.truncatedTo(ChronoUnit.HOURS)
.plusMinutes((long) 15 * (original.getMinute() / 15));
break;
default:
nearest = original;
}
return nearest;
}
Вы можете попробовать это с помощью этого модульного теста
@Test
void roundToTheNearestInterval() {
//given
LocalTime originalTime1 = LocalTime.of(6, 31, 15);
LocalTime originalTime2 = LocalTime.of(19, 13, 42);
LocalTime originalTime3 = LocalTime.of(6, 37, 11);
LocalTime originalTime4 = LocalTime.of(19, 40, 34);
Integer measurementInterval_5min = 5;
Integer measurementInterval_15min = 15;
MyService myService = new MyService();
//when
LocalTime rounded1_5min = myService.roundToTheNearestInterval(originalTime1, measurementInterval_5min);
LocalTime rounded2_5min = myService.roundToTheNearestInterval(originalTime2, measurementInterval_5min);
LocalTime rounded1_15min = myService.roundToTheNearestInterval(originalTime3, measurementInterval_15min);
LocalTime rounded2_15min = myService.roundToTheNearestInterval(originalTime4, measurementInterval_15min);
//then
assertEquals(LocalTime.of(6, 30, 0), rounded1_5min);
assertEquals(LocalTime.of(19, 15, 0), rounded2_5min);
assertEquals(LocalTime.of(6, 30, 0), rounded1_15min);
assertEquals(LocalTime.of(19, 45, 0), rounded2_15min);
}