asda asda
asda asda

Reputation: 35

Generate specific intervals between two time/date in Java

I want to generate intervals between two given date/time.
For instance, say for 24 hour format (HH:MM), I have these two endpoints, 00:00 and 11:51, and suppose I want to partition it in 24 pieces. So my calculation is like this:

(hour * 3600 + min * 60) / 24

If I use calendar.add(Calendar.SECOND, (hour * 3600 + min * 60) / 24), I am getting wrong dates/time. My calculation is double and I think calendar.add() does not support double. Like it is taking 28.883 as 29.

In essence I want something like this:

now : 15:57
today start : 00:00 (24hh)
output : 00:00, 00:47.85, …, 15:57

Upvotes: 0

Views: 2083

Answers (3)

Anonymous
Anonymous

Reputation: 86272

Here’s a variant of MC Emperor’s fine code. I wanted to leave the math to the library class. Duration has methods dividedBy and multipliedBy that we can use to our advantage.

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

Output:

[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]

Is there a rounding problem? With a start time in whole minutes and 24 pieces there won’t be since 24 divides evenly into the number of nanoseconds in a minute. With another number of pieces you may decide whether the slight inaccuracy is worth worrying about. If it is, for each partitioning time multiply before you divide.

Upvotes: 0

MC Emperor
MC Emperor

Reputation: 22977

The actual problem with your code is that you are performing integer division. I assume both hour and min are defined as integer types. The formula (hour * 3600 + min * 60) / 24 always yields an integer type. If you change the code to (hour * 3600 + min * 60) / 24d the expression yields a floating point value at least.

The next problem is indeed that Calendar.add(int field, int amount) accepts only an integer as second argument. Of course, if you are passing Calendar.SECOND as first argument, then your precision is not higher than seconds. You can use Calendar.MILLISECOND to get a higher precision.

However, I suggest using the new Java Date and Time API, instead of the troublesome old 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);

Upvotes: 1

rghome
rghome

Reputation: 8819

You need to save your start date in a calendar object and then when you generate each division use the formula:

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

That way the arithmetic errors that you get by dividing by 24 (or whatever) are not accumulated.

Upvotes: 0

Related Questions