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
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);
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.
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.
Why does my loop not work?
I'm trying to increment by 5 and the output the time it took to increment with the linear method
for(n=5;n<=10;n=n+5) {
long startTime= System.currentTimeMillis();
System.out.println(startTime);
System.out.println("\nOddanaci(" + n +")\n" );
linear(n);
long endTime= System.currentTimeMillis();
long diff= endTime - startTime;
System.out.println("\n\nThe Total time it took to run this program is\n"+diff);
}
my output
Please enter the a non-negative value to find its Oddonacci sequence: 3
Here is the Oddonacci(3) sequence
1 1 1
The method has been called 1 times.
1537756698523
Oddanaci(5)
1 1 1 3 5
The Total time it took to run this program is
1
1537756698524
Oddanaci(10)
1 1 1 3 5 9 17 31 57 105
The Total time it took to run this program is
0
Why does it output as zero? Doesn't n iterate?
This question already has answers here:
How to convert minutes to Hours and minutes (hh:mm) in java
(15 answers)
Closed 8 years ago.
I need to convert minutes to hours and minutes in java, so i do this
java:
long minutes = offer.getDuration();
long hours = minutes / 60;
long minnutesRemaining = minutes % 60;
trainOffer.setDuration(hours+"h"+minnutesRemaining);
output:
minutes = 129
hours = 2
minnutesRemaining = 9
how can i do for have minnutesRemaining = 09 ?
Use String.format to format the output:
System.out.println(String.format("%02d", minnutesRemaining ));
I came up with a question that initially was going to be a Q/A style question.
The original question:
How much does a higher scale in BigDecimal#divide() affect performance?
So, I created this SSCCE:
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String args[]) {
int[] scales = new int[] {1, 10, 50, 100, 500, 1000, 5000, 100000, 1000000};
for(Integer scale : scales) {
long start = System.nanoTime();
BigDecimal.ONE.divide(BigDecimal.valueOf(7), scale, RoundingMode.HALF_UP);
long end = System.nanoTime();
long elapsed = end - start;
String elapsed_str = String.format("%d mins, %d secs, %d millis, %d nanos",
TimeUnit.NANOSECONDS.toMinutes(elapsed),
TimeUnit.NANOSECONDS.toSeconds(elapsed) - TimeUnit.MINUTES.toSeconds(TimeUnit.NANOSECONDS.toMinutes(elapsed)),
TimeUnit.NANOSECONDS.toMillis(elapsed) - TimeUnit.SECONDS.toMillis(TimeUnit.NANOSECONDS.toSeconds(elapsed)),
elapsed - TimeUnit.MILLISECONDS.toNanos(TimeUnit.NANOSECONDS.toMillis(elapsed))
);
System.out.println("Time for scale = " + scale + ": " + elapsed_str);
}
}
}
The output was thus:
Time for scale = 1: 0 mins, 0 secs, 2 millis, 883903 nanos
Time for scale = 10: 0 mins, 0 secs, 0 millis, 13995 nanos
Time for scale = 50: 0 mins, 0 secs, 1 millis, 138727 nanos
Time for scale = 100: 0 mins, 0 secs, 0 millis, 645636 nanos
Time for scale = 500: 0 mins, 0 secs, 1 millis, 250220 nanos
Time for scale = 1000: 0 mins, 0 secs, 4 millis, 38957 nanos
Time for scale = 5000: 0 mins, 0 secs, 15 millis, 66549 nanos
Time for scale = 100000: 0 mins, 0 secs, 500 millis, 873987 nanos
Time for scale = 1000000: 0 mins, 50 secs, 183 millis, 686684 nanos
As the order of magnitude increases, the performance is affected exponentially. But what had me scratching my head were these lines:
Time for scale = 1: 0 mins, 0 secs, 2 millis, 883903 nanos
Time for scale = 10: 0 mins, 0 secs, 0 millis, 13995 nanos
Time for scale = 50: 0 mins, 0 secs, 1 millis, 138727 nanos
Time for scale = 100: 0 mins, 0 secs, 0 millis, 645636 nanos
Time for scale = 500: 0 mins, 0 secs, 1 millis, 250220 nano
It appears that a scale of 10 is optimal for BigDecimal#divide()? And a scale of 100 is faster than 50? I thought this might just be an anomaly, so I ran it again (this time, omitting the highest two scales because I didn't want to wait 50 seconds :)) and this is the result:
Time for scale = 1: 0 mins, 0 secs, 3 millis, 440903 nanos
Time for scale = 10: 0 mins, 0 secs, 0 millis, 10263 nanos
Time for scale = 50: 0 mins, 0 secs, 0 millis, 833169 nanos
Time for scale = 100: 0 mins, 0 secs, 0 millis, 487492 nanos
Time for scale = 500: 0 mins, 0 secs, 0 millis, 802846 nanos
Time for scale = 1000: 0 mins, 0 secs, 2 millis, 475715 nanos
Time for scale = 5000: 0 mins, 0 secs, 16 millis, 646117 nanos
Again, 10 is considerably faster than 1, and 100 is again faster than 50.
I tried again and again, and 100 was always faster than 50. And a scale of 1 was always slower than everything less than 1000.
Anyone have an explanation?
Java code is optimised dynamically but the first time you run it, it has to be loaded. To avoid confusing results caused by the code being re-compiled as you run it, I suggest
doing your longest run first, not last.
run the test for at least 2 seconds.
ignore the first run of at least 3 to 5 runs (You only have one in this case)
I would keep the scale simple so you can compare all the results. In your case I would do each one at least 1000 times and print the average in micro-seconds.
This is kind of hard to explain but I need to come up with an algorithm that will use these 14 value buckets to move through it based on the day and assign them to these buckets..
For example, if started today (monday), value would go to bucket #1, for sunday it would be #7, sunday after #14 and the next day, on monday, it would use the #1 bucket again..
Any help appreciated.
Count the days and use modulo:
int bucket = (days % 14) + 1
If you start at 0; you can leave out the +1.
Calculating the day:
long start = ...
long current = System.currentTimeMillis();
int bucket = (int) ( ((start - current) / (1000 * 60 * 60 * 24)) % 14 )