Java date class interesting - java

End date was being computed to be earlier than the start date
Date startDate = new Date();
Date endDate = new Date(startDate.getTime() + (24 * 3600000 * 42));
System.out.println(startDate);
System.out.println(endDate);
output :
Tue Sep 17 01:46:31 EEST 2013
Mon Sep 09 08:43:43 EEST 2013
why the output is not correct ?

Your integer arithmetic has overflowed. The maximum possible value of an int is 2147483647 or Integer.MAX_VALUE (a little over 2 billion), but multiplying your integer literals would yield 3628800000 (about 3.6 billion). The result is a negative number (-666167296), and an earlier date.
Try casting one of your literals as a long to force long arithmetic (or use long literals):
( (long) 24 * 3600000 * 42)
or
(24L * 3600000 * 42)
This operation is well within the range of long values (max value 9223372036854775807, over 9 quintillion).

24 * 3600000 * 42 is 3,628,800,000 which does not fit into an int. Rollover occurs. Force the use of a long by casting one of the factors:
24L * 3600000 * 42

The number you're trying to add is 24 * 3600000 * 42 which is equal to 3,628,800,000. This is larger than 2,147,483,647 which is the maximum value that can be represented with the given data type. What you're experiencing is an overflow, meaning that after crossing the maximum value, the number loops back to its lowest value, which is in the negative. Therefore, you're adding a negative value to the date.

Related

Android studio warns about integer multiplication implicitly cast to long. How to fix this?

private static boolean isOverDate(long targetDate, int threshold) {
return new Date().getTime() - targetDate >= threshold * 24 * 60 * 60 * 1000;
}
I am using above function and Android Studio warns me about:
threshold * 24 * 60 * 60 * 1000: integer multiplication implicitly cast to long
How to fix this? And why it warns?
OK, so this is a bit complicated to unpick.
On the LHS (left hand side) of the >= expression we have:
new Date().getTime() - targetDate
The type of that expression is long because targetDate is declared as long.
On the RHS we have:
threshold * 24 * 60 * 60 * 1000
That is an int because all of the operands are ints.
However that expression is likely to overflow. The value of 24 * 60 * 60 * 1000 is a "rather large", and when you multiply it by threshold, the resulting value is liable to be too big to represent as an int. If it does overflow, then the result will be truncated, and the >= test will give the wrong result.
So ... the compiler is suggesting that you should do the RHS calculation using long arithmetic. The simple way would be to declare threshold as a long. But you could also cast it to a long as in:
((long) threshold) * 24 * 60 * 60 * 1000
Since max_int is 2 147 483 648.
If your threshold is more than 25 (25 * 24 * 60 * 60 * 1000 = 2.160.000.000), it will higher than int can hold. So you will need to cast to long or the result may be incorrect.
Reference: https://stackoverflow.com/a/42671759/4316327
If an integer multiplication overflows, then the result is the
low-order bits of the mathematical product as represented in some
sufficiently large two's-complement format. As a result, if overflow
occurs, then the sign of the result may not be the same as the sign of
the mathematical product of the two operand values.
Solution:
long timeToCheck = threshold * 24 * 60 * 60 * 1000L;
return new Date().getTime() - targetDate >= timeToCheck;
or single line (different here is L after last number, it will understand that you will change type to long)
return new Date().getTime() - targetDate >= threshold * 24 * 60 * 60 * 1000L;
or casting
return new Date().getTime() - targetDate >= (long) threshold * 24 * 60 * 60 * 1000;

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
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.

how to get number of micro seconds in a day

I want to get the number of micro seconds in a day
so I tried as per below
long microDay = 24 * 60 * 60 * 1000 * 1000;
for which I am expecting value as 86400000000 but when I print it
System.out.println(microDay);
The value is 500654080
After spending 3 hours and breaking my head to know the reason,final I found that java think 24,60 and 1000 as int values and int*int =int but the maximum value of int is 2147483647 so it cant store 86400000000 and hence it the output is 500654080 (but I am not sure)
In the second case I wanted to calculate miliseconds in a day and the formula goes like this
long miliDay = 24 * 60 * 60 * 1000;
System.out.println(miliDay );
output 86400000
now when I did
System.out.println(microDay/ miliDay);
output 5
but when I tried this in a calculator 500654080/86400000= 5.794607407407407
why there is different in result?
You're performing 32-bit integer arithmetic, as every operand in 24 * 60 * 60 * 1000 * 1000 is an int... but the result is bigger than Integer.MAX_VALUE, so it's overflowing (just as you suspected). (This is actually happening at compile-time in this case, because it's a compile-time constant, but the effect is the same as if it happened at execution time.)
Effectively, each operation is truncated to 32 bits. As it happens, only the final multiplication by 1000 takes the result over 231 - 86400000 is fine.
86400000000 in binary is:
1010000011101110101110110000000000000
^
\- Bit 33
So after overflow, we just chop any leading bits until we've got 32:
00011101110101110110000000000000
And that value is 500654080.
Just use long instead, e.g.
long microDay = 24L * 60L * 60L * 1000L * 1000L;
(You definitely don't need all those constants to be of type long, but being consistent means it's obvious that all the operations will be performed using 64-bit arithmetic, with no need to consider associativity etc.)
A better approach, however, would be to use TimeUnit:
long microDay = TimeUnit.DAYS.toMicroseconds(1);
As for the division part, you're performing integer division - so the result is the integer part, rounded towards 0. If you want floating point arithmetic, you need to cast one of the operands to float or double... although if you start off with the right values, of course, you should get an exact integer anyway (1000).
For the first part, put a "L" at the end of one (or more) of the constants and Java will then use long arithmetic. e.g.
long microDay = 24L * 60 * 60 * 1000 * 1000;
Addendum: Why did you get 500654080?
86400000000 decimal = 141DD76000 hex.
But, the integer only holds 32 bits, which is 8 "digits". So you lose the leading 14 and retain 1DD76000 hex.
Converting that to decimal gives 500654080.
As for the division, when you divide ints by ints (or longs by longs) Java returns the result as an int or long, so it has to truncate (or round, but Java chose to truncate) the result to 5 instead of 5.7946... Force it to do floating point arithmetic by casting one of the values to a double, e.g.
System.out.println((double)microDay/ miliDay);
When you are performing a division between 2 integers, the results are an integer. The results of the arithmetic operation will be rounded down to the nearest integer.
int i = 5 / 2; // 2.5 is rounded down to 2
if you want the output to include the decimal precision, you will need to use a different primitive data type and explicitly specify your operands to be doubles.
double j = 5 / 2; //2.0 as 5 / 2 yields and integer 2 which will be casted to a double
double j = 5 / 2.0; //2.5 explicit usage of a double will tell the compiler to return the results in double
The nuclear operations inside
long microDay = 24 * 60 * 60 * 1000 * 1000;
are all Integers specific. Max value of Integer object is 2147483647. Which exceeds the original output which is long.
Simply specifying long to variable doesn't mean all operations using [ * ] will be done using long instances. All operations done in assignment became sort of truncated.
Solution is to explicitly specify that all nuclear operations should happen over long instance and not int instances.
long microDay = 24L * 60L * 60L * 1000L * 1000L;

Positive division, negative result in Java

I'm really puzzled by this. I'm dividing two positive numbers and getting a negative result (I'm using Java).
long hour = 92233720368L / (3600 * 1000000 );
I got as result -132.
But if I divide them as two long numbers, I get the right result:
long hour1 = 92233720368L / (3600000000L );
Then I get as result: 25
I'm wondering why it occurs...
Thank you in advance! :)
You must add L at the end of 3600 or 1000000:
Example:
long hour = 92233720368L / (3600 * 1000000L );
Here's what's hapenning:
System.out.println(3600 * 1000000); // Gives -694967296 because it exceeds the max limit of an integer size. So 92233720368L / -694967296 = -132
That's exactly what's happening in your division, the dominator is an integer and is considered as negative number for the reason I stated above. So in order to consider the multiplication result of type long you should add L after 3600 or after 1000000
It interprets 3600 and 10000000 as type int which cannot hold enough information to represent their product, and so you get a different number. You'd have to declare them both as type long to get the correct result.

Incorrect Multiplication Result [duplicate]

This question already has answers here:
1000 * 60 * 60 * 24 * 30 results in a negative number [duplicate]
(4 answers)
Closed 8 years ago.
I'm trying to understand why this multiplication results in an incorrect value:
long max = (60 * 24 * 60 * 60 * 1000);
This should = 5,184,000,000
But in my Java program it = 889,032,704
Any idea why this is the case?
All of the values you're multiplying are ints so the result is an int which is cast to a long after overflow has already happened. Make one of the factors a long so that they are multiplied using 64b instructions
Try
long max = (60L * 24L * 60L * 60L * 1000L);
The L suffix specifies that the constant is a long value, not an int constant.
The language specification says
An integer literal is of type long if it is suffixed with an ASCII letter L or l (ell); otherwise it is of type int (§4.2.1).
and the section on multiplication says
The type of a multiplicative expression is the promoted type of its operands.
and type promotion of two ints leaves them as ints:
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int
This is due to integer overflow. Your right-side product is represented as int (default type of all operands) and it obliviously can't hold your "long" value.
Just make the first factor of your product long, either as long constant 60L, as in Mike's answer, or cast it explicitly (long) 60 :
long max = (long) 60 * 24 * 60 * 60 * 1000;
and you will get what you expect.

Categories