Генерация определенных интервалов между двумя датой / временем в Java - PullRequest
0 голосов
/ 27 марта 2019

Я хочу создать интервалы между двумя данными датой / временем.
Например, скажем, для 24-часового формата (HH:MM), у меня есть эти две конечные точки, 00:00 и 11:51, и, предположим, я хочу разбить его на 24 части. Итак, мой расчет таков:

(hour * 3600 + min * 60) / 24

Если я использую calendar.add(Calendar.SECOND, (hour * 3600 + min * 60) / 24), я получаю неправильные даты / время. Мой расчет двойной, и я думаю, calendar.add() не поддерживает двойной. Как будто он принимает 28,883 за 29.

По сути, я хочу что-то вроде этого:

сейчас: 15: 57
сегодня начало: 00:00 (24ч)
выход: 00:00, 00: 47,85,…, 15: 57

Ответы [ 3 ]

1 голос
/ 27 марта 2019

Фактическая проблема с вашим кодом заключается в том, что вы выполняете целочисленное деление.Я предполагаю, что и hour, и min определены как целочисленные типы.Формула (hour * 3600 + min * 60) / 24 всегда дает целочисленный тип.Если вы измените код на (hour * 3600 + min * 60) / 24d, выражение даст по крайней мере значение с плавающей запятой.

Следующая проблема в том, что Calendar.add(int field, int amount) принимает только целое число в качестве второго аргумента.Конечно, если вы передаете Calendar.SECOND в качестве первого аргумента, то ваша точность не превышает секунды.Вы можете использовать Calendar.MILLISECOND для получения более высокой точности.

Однако я предлагаю использовать новый Java Date and Time API вместо хлопотливого старого API:

LocalTime startTime = LocalTime.of(0, 0);
LocalTime endTime = LocalTime.of(11, 51);
long span = Duration.between(startTime, endTime).toNanos();

final int n = 23; // Number of pieces
LongStream.rangeClosed(0, n)
    .map(i -> i * span / n)
    .mapToObj(i -> startTime.plusNanos(i))
    .forEach(System.out::println);
0 голосов
/ 28 марта 2019

Вот вариант точного кода MC Emperor . Я хотел оставить математику в классе библиотеки. Duration имеет методы dividedBy и multipliedBy, которые мы можем использовать в своих интересах.

    LocalTime startTime = LocalTime.of(0, 0);
    LocalTime endTime = LocalTime.of(11, 51);

    final int n = 24; // Number of pieces
    Duration piece = Duration.between(startTime, endTime).dividedBy(n);
    LocalTime[] partitionTimes = IntStream.rangeClosed(0, n)
        .mapToObj(i -> startTime.plus(piece.multipliedBy(i)))
        .toArray(LocalTime[]::new);
    System.out.println(Arrays.toString(partitionTimes));

Выход:

[00:00, 00: 29: 37.500, 00:59:15, 01: 28: 52.500, 01:58:30, 02: 28: 07.500, 02:57:45, 03: 27: 22.500, 03:57, 04: 26: 37.500, 04:56:15, 05: 25: 52.500, 05:55:30, 06: 25: 07.500, 06:54:45, 07: 24: 22.500, 07:54, 08: 23: 37.500, 08:53:15, 09: 22: 52.500, 09:52:30, 10: 22: 07.500, 10:51:45, 11: 21: 22.500, 11:51]

Есть ли проблема округления? Время начала в целых минутах и ​​24 штуки не будет, поскольку 24 делится поровну на количество наносекунд в минуту. С другим количеством частей вы можете решить, стоит ли беспокоиться о небольшой неточности. Если это так, для каждого времени разбиения умножьте, прежде чем делить.

0 голосов
/ 27 марта 2019

Вам необходимо сохранить дату начала в объекте календаря, а затем при создании каждого подразделения использовать формулу:

startCalendar.add(Calendar.Second, count * (hour * 3600 + min * 60) / 24))

Таким образом, арифметические ошибки, полученные при делении на 24 (или что-то еще), не накапливаются.

...