Подтвердить что ты не робот

Как округлить время до ближайшего квартального часа в java?

Учитывая сегодняшнее время, например. 14:24, как мне добраться до 2:30 вечера?

Аналогично, если время было 2:17 вечера, как мне добраться до раунда до 2:15 вечера?

4b9b3361

Ответ 1

Округление

Вам нужно будет использовать modulo для усечения четверти часа:

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, это также нормально (замена для последней строки, действительна только в том случае, если календарь lenient):

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);

Ответ 2

Если вы просто хотите округлить, это более читаемая версия, используя 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

Ответ 3

Это просто, найдите число кватеров с 1970 года как двойное, округлите его и умножьте на 15 минут:

long timeMs = System.System.currentTimeMillis();

long roundedtimeMs = Math.round( (double)( (double)timeMs/(double)(15*60*1000) ) ) * (15*60*1000) );

Задайте для этого объект Date или Calendar.

Ответ 4

С ответом выше вы получаете весь интересный код для обработки переполнения часов, дней и т.д.

Я использовал бы время в ms с эпохи.

добавить 7.5minutes или 7.5x60x1000 = 450000

и усечь до кратного 900000

new Date(900000 * ((date.getTime() + 450000) / 900000))

Это работает, потому что время, в которое начинается время ms, составляет 00:00:00. И поскольку все часовые пояса в мире изменяются с шагом 15 минут, это не влияет на округление до кварталов.

(Упс, у меня было слишком много 0 и забыли некоторые важные круглые скобки: все еще слишком рано)

Ответ 5

Прокомментированная реализация для 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;
  }

Источник: сам

Ответ 6

Замечательный пост, большое спасибо, ребята! Это было именно то, что мне нужно:)

Здесь мой код основан на работе jour.

My usecase "Учитывая это 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()); 

Ответ 7

Вы можете использовать этот простой код...

int mode = min % 15;
if (mode > 15 / 2) {
    min = 15 - mode;
} else {
    min = 0 - mode;
}
cal.add(Calendar.MINUTE, min);

Ответ 8

Возможно, вы можете использовать служебную библиотеку для управления датами, здесь, например, у вас есть круглый метод, который может быть вам полезен:

http://commons.apache.org/lang/api-2.4/org/apache/commons/lang/time/DateUtils.html#round%28java.util.Calendar,%20int%29

Вот пример кода:

    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));

Ответ 9

public static Date getCurrentDateTimeWithQuarterRounding() {
    final Calendar calendar = new GregorianCalendar();
    calendar.setTime(new Date());
    calendar.set(Calendar.MILLISECOND, 0);
    calendar.set(Calendar.SECOND, 0);
    final int minutes = calendar.get(Calendar.MINUTE);

    if (minutes < 15) {
        calendar.set(Calendar.MINUTE, 0);
    } else if (minutes >= 45) {
        calendar.set(Calendar.MINUTE, 45);
    } else if (minutes < 30) {
        calendar.set(Calendar.MINUTE, 15);
    } else {
        calendar.set(Calendar.MINUTE, 30);
    }

    return calendar.getTime();
}

Ответ 10

Если у вас есть минуты, вы можете объединить их со следующей функцией:
  int minutes = i % 15 < 8 ? i / 15 * 15 : (i / 15 + 1) * 15;

Ответ 11

minutes = (int) (Math.round(minutes / 15.0) * 15.0);

Ответ 12

Используя некоторый код, который я нашел в 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 INFO 15: 07,15: 00
2016-08-16 15:14:31 INFO 15: 08,15: 15
2016-08-16 15:14:31 INFO 15: 09,15: 15
2016-08-16 15:14:31 ИНФОРМАЦИЯ 15: 10,15: 15

Ответ 13

Еще один альтернативный подход с использованием 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);