0

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

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
asda asda
  • 35
  • 1
  • 7
  • 2
    I don't quite get it. First of all you should use the new date time api that was introduced with Java 8 instead of the old one. Then you need to realize that you should use the smallest time unit you want to have precision for, i.e. if you want to be precise to the second then 28.883 seconds can't be used, you need to round that to 29 (or truncate to 28). If you really need those 883 milliseconds then use milliseconds as your base time unit - but do you _really_ need that precision? What do you want to achieve with that? – Thomas Mar 27 '19 at 09:06
  • Actually i am because i want to draw linechart between 00:00-(now hour:min). I have 24 list item. In linechart i am dividing these to 6 pieces.So dates show wrong. – asda asda Mar 27 '19 at 09:11
  • You should provide a more elaborate example of what dates you'd want exactly and what you get instead. As I said, if you're using second precision then 28.883 seconds cannot be used - it has to be 28 or 29. If the problem is that the error is accumulating like rghome suspects then do as he suggested. – Thomas Mar 27 '19 at 09:30

3 Answers3

1

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);
MC Emperor
  • 22,334
  • 15
  • 80
  • 130
0

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.

rghome
  • 8,529
  • 8
  • 43
  • 62
0

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.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161