Finding age on different planets - java

I'm writing a program that asks the user for their birthdate and then calculates their age in years of different planets. I am not suppose to assume how the birthdate is to be entered except that there is one white space between each number.
The code I have right now does not meet these specifications right now and I'm not sure how to write it otherwise. I am also having problem calculating what my age would be today. When I enter my birthdate and print out age, it currently tells me that I'm 407 yet when I print out dateBirth and today, both of those dates are correct.
System.out.print("Please enter your birthdate (mm dd yyyy): ");
birthdate = scan.nextLine();
DateFormat df = new SimpleDateFormat("MM dd yyyy");
Date dateBirth = df.parse(birthdate);
Calendar calBirth = new GregorianCalendar();
calBirth.setTime(dateBirth);
Calendar calDay = new GregorianCalendar();
today = calDay.getTime();
age = (today.getTime() - dateBirth.getTime()) / (1000 * 60 * 60 * 24 * 365);

1000 * 60 * 60 * 24 * 365 is actually 31536000000 which is bigger than Integer.MAX_VALUE this causes an overflow. As an integer it would be evaluated to 1471228928 which leads to the wrong result.
The solution is append the letter L to one of your constants
long div = ( 1000 * 60 * 60 * 24 * 365L );
long age = ( today.getTime() - dateBirth.getTime() ) / div;

You should check if the expression 1000 * 60 * 60 * 24 * 365 evaluates to the result you are expecting and if not, find a way to get the expected result. Perhaps you should even consider that on earth, we have so called leap years and that you could tag your question as homework.

1000 * 60 * 60 * 24 * 365
Is an int, but its to long to hold it. Make one of these a long, like:
1000L * 60 * 60 * 24 * 365

Related

Java, Intellij : Replacing numeric overflow expression with one which doesn't overflow

I have a scheduled job running, where I want to calculate time till last 30 days. For that I am getting a warning that numeric overflow detected in expression. How can I safely give 30 days?
#Override
#Scheduled(cron = "0 5 5 * * ?")
public void deleteRepliesAutomatically() {
if(schedulerActive.equals("true")) {
Session session = this.sessionFactory.getCurrentSession();
long now = System.currentTimeMillis();
// Below line gives warning.
long nowMinus1Week = now - (1000 * 60 * 60 * 24 * 30);
Timestamp nowMinus1WeekAsTimeStamp = new Timestamp(nowMinus1Week);
Query query = session.createQuery("from Replies as cm where cm.sortTimeStamp <:limit");
query.setParameter("limit", nowMinus1WeekAsTimeStamp);
List<Replies> repliesList = query.list();
for (Replies replies : repliesList) {
session.delete(replies);
session.flush();
}
}
}
Thank you.
The problem is your expression (1000 * 60 * 60 * 24 * 30) (resulting in 2.592.000.000) is a pure int-computation that is overflowing (Integer.MAX_VALUE is 2.147.483.647).
Just make e.g. the first number a long by adding a L:
(1000L * 60 * 60 * 24 * 30)
This will make the whole computation using the long datatype that is large enough to hold the value.
The answer of piet.t is in correct to fix the issue at hand.
But it would be better maintanable to use TimeUnit enum to calculate from one unit to another.
For example to have milliseconds of one week:
long millis = TimeUnit.DAYS.toMillis(7);
You can also do a import static for DAYS.

Difference between casting to int and intValue() method in Java

I have a long value that needed to be converted to an integer. When I use casting, time to time integer value gives a minus value, which is not expected. But when I use the intValue() method in Long, the expected results comes.
I want to know the difference of casting and using intValue() method
Casting Example
int days = (int) ((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24));
intValue Example
int days = ((Long) ((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24))).intValue();
Edit: More Elaborate Example to show minus values without overflow as suggested in comments. Before casting the result is 27. When casting, the value becomes -22. But if intValue method is used, the result is 27.
Code
System.out.println("nextDeliveryDate = " + nextDeliveryDate);
System.out.println("nextDeliveryDate.getTime() = " + nextDeliveryDate.getTime());
System.out.println("expectedDeliveryDate = " + expectedDeliveryDate);
System.out.println("expectedDeliveryDate.getTime() = " + expectedDeliveryDate.getTime());
System.out.println("nextDeliveryDate.getTime() - expectedDeliveryDate.getTime() = " + (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()));
System.out.println("(nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24) = " + (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24));
System.out.println("((int) (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24)) = " + ((int) (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24)));
System.out.println("((Long) ((nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24))).intValue() = " + ((Long) ((nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24))).intValue());
Results
Info: nextDeliveryDate = Thu May 14 00:00:00 IST 2015
Info: nextDeliveryDate.getTime() = 1431541800000
Info: expectedDeliveryDate = Fri Apr 17 00:00:00 IST 2015
Info: expectedDeliveryDate.getTime() = 1429209000000
Info: nextDeliveryDate.getTime() - expectedDeliveryDate.getTime() = 2332800000
Info: (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24) = 27
Info: ((int) (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24)) = -22
Info: ((Long) ((nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24))).intValue() = 27
I don't think your results should be different, because here is what the Long.intValue() method does:
public int intValue() {
return (int)value;
}
Something isn't right with your control flow between those two lines.
You can try this test below:
Calendar now = Calendar.getInstance();
Date fromDate = now.getTime();
now.add(Calendar.YEAR, 10);
Date toDate = now.getTime();
System.out.println("line 0: " + (toDate.getTime() - fromDate.getTime()));
System.out.println("line 1: " + (int)(toDate.getTime() - fromDate.getTime()));
System.out.println("line 2: " + new Long((toDate.getTime() - fromDate.getTime())).intValue());
int days = (int) ((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24));
System.out.println("line 3: " + days);
days = ((Long) ((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24))).intValue();
System.out.println("line 4: " + days);
You may be hitting int overflow. If the difference between toDate.getTime() and fromDate.getTime() is greater than 2.147 bilion (i.e. Integer.MAX_VALUE), it won't be possible to express it as an integer and it will just wrap and change to minimum value - e.g. Integer.MAX_VALUE + 100 will give you negative result.
You should do all the operations on longs first until you are sure that it is small enough to be cast to int without overflow. I think both your examples are correct, the first is definitely much clearer than the other.
Also, remember that expressions like 1000 * 60 * 60 * 24 are integers and they may overflow too. For example, the number of miliseconds in a month is 31 * 24 * 3600 * 1000, however written like this it returns -1616567296.
EDIT: Let me explain the output you have attached in your edit :
Info: nextDeliveryDate.getTime() - expectedDeliveryDate.getTime() = 2332800000
Info: (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24) = 27
Info: ((int) (nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24)) = -22
Info: ((Long) ((nextDeliveryDate.getTime() - expectedDeliveryDate.getTime()) / (1000 * 60 * 60 * 24))).intValue() = 27
I will also refer to nextDeliveryDate.getTime() - expectedDeliveryDate.getTime() as x. So we can declare it as long x = 2332800000 (declaring int will give compilation error as it is too large to be hold in 4 bytes).
In the first line, you have x / something, something is an int and x is long, so something will be converted to long, the final result is long.
In the second line, you have ((int) x) / something, so long 2332800000 is cast to integer giving -1962167296 and then you have -1962167296 / something.
In your last line, you have (Long) (x / something) which is effectively the same case as first one.
There is no difference, this code
public static void main(String[] args) {
System.out.println((int) (21470000000l));
System.out.println((int) ((Long)21470000000l).intValue());
}
Has this output :
-4836480
-4836480
Therefore you have different values in your toDate and fromDate.
If the value exceed the MAX of integer, you never get the "expected" result, because it just cant fit in there.
Firstly, to explain a little about the difference between casting to int and IntValue() method in Java.
IntValue() is a method in the Integer class (and other wrapper classes).
What IntValue will do is get the integer and return it as an int type.
Note that int is an primitive datatype and Integer is a class that holds this datatype. It's like a wrapper, because there are data structures that cannot hold primitive datatypes. See this SO question for more info
Basically:
Converting an int to Integer is called boxing.
Converting an Integer to int is called unboxing
As noted in the SO question I linked.
However, as for your example, this is a little different because of the types involved. The difference is that you perform all operations as a Long datatype, which holds a lot more numbers than an int first, for accuracy, then only convert it to an int. So your IntValue() method is from the long datatype, which Java7 docs mention of it's use. Basically it just changes it from a long to an int, which still can cause overflows.
Note that Long is the wrapper class for the primitive datatype long (in which the primitive datatype does not have the IntValue() method)
So the difference in values you get may be because when you did the simple cast from Long -> int primitive datatypes, there wasn't an overflow.
I suggest you test out your code with really large numbers that don't change (unlike date,time which is different every time you fetch it)
Solving the overflow problem
You also might be interested in how to safely cast a long to an int in java as discussed in this SO question as an alternative solution for handling the overflow possibility.
Another way I would suggest is to first cut down the precision (hence you lose precision) into a safe enough value (and precise enough one) before casting it back to an int for use.
Or, use BigIntegers, which are immutable arbitrary-precision integers. see the the documentation on this class and this SO Q&A on how to use it. It is definitely going to add complexity to the code as they are immutable.
This other SO question has good solutions that give nice methods on detecting overflow in ints and longs which I also recommend as well.

Minus date calculation with GWT

Here is my try to do date minus for GWT:
Date from = new Date();
Date to = new Date();
if(filter.equals(DATE_FILTER.PAST_HOUR)){
minusHoursToDate(to, 1);
} else if(filter.equals(DATE_FILTER.PAST_24_HOURS)){
minusHoursToDate(to, 1 * 24);
} else if(filter.equals(DATE_FILTER.PAST_WEEK)){
minusHoursToDate(to, 1 * 24 * 7);
} else if(filter.equals(DATE_FILTER.PAST_MONTH)){
minusHoursToDate(to, 1 * 24 * 7 * 4);
} else if(filter.equals(DATE_FILTER.PAST_YEAR)){
minusHoursToDate(to, 1 * 24 * 7 * 4 * 12);
}
public static void minusHoursToDate(Date date, int hours){
date.setTime(date.getTime() - (hours * 3600000));
}
The problem I see here is with the calculation in terms of month and year. As months is not always 4-week aligned and a year is also affected.
What could be the best calculation for subtracting month & year?
Since java.util.Calendar is unsupported in GWT because of the complexity needed for its implementation, the final JS size, etc, I would go with a simple and lightweight solution based on JS.
Apart from the java Date implementation, in GWT we have the JsDate wrapper which includes all the methods available in the native JS date, so subtracting a month or a year should be as simpler as:
int months = -2;
int years = -3;
JsDate j = JsDate.create(new Date().getTime());
j.setMonth(j.getMonth() + months);
j.setFullYear(j.getFullYear() + years);
Date d = new Date((long)j.getTime());
You can do the same to manipulate other units:
getDate() Returns the day of the month (from 1-31)
getDay() Returns the day of the week (from 0-6)
getFullYear() Returns the year (four digits)
getHours() Returns the hour (from 0-23)
getMilliseconds() Returns the milliseconds (from 0-999)
getMinutes() Returns the minutes (from 0-59)
getMonth() Returns the month (from 0-11)
getSeconds() Returns the seconds (from 0-59)

System.currentTimeMillis() giving wrong time in hours

I'm trying to get my app to display a time, and for that I need to get the android's minutes and hours. I'm trying to use currentTimeMillis(), but I'm getting the wrong number for the hours. Here's my code for the hours and minutes using the systems clock.
int defday = (int) (System.currentTimeMillis() / (1000 * 60 * 60 * 24));
int defhour = (int) (System.currentTimeMillis() - (defday * 1000 * 60 * 60 * 24))
/ (1000 * 60 * 60);
int defmin = (int) (System.currentTimeMillis()
- (defhour * 1000 * 60 * 60) - (defday * 1000 * 60 * 60 * 24))
/ (1000 * 60);
After I run the app, the time shows the time as 5:36 even though the current time is 1:36. What am I doing wrong?
Create a Calendar object:
long millis=System.currentTimeMillis();
Calendar c=Calendar.getInstance();
c.setTimeInMillis(millis);
After this you can get the fields from the Calendar object:
int hours=c.get(Calendar.HOUR);
int minutes=c.get(Calendar.MINUTE);
Then:
int MinutesHours=(hours*60)+minutes;
To go back, you can use the set method in Calendar:
Calendar c=Calendar.getInstance();
c.set(Calendar.MINUTE,minutes);
long millis=c.getTimeInMillis();
References
How to measure the a time-span in seconds using System.currentTimeMillis()?
currentTimeMillis() to Years, days, and minutes, and backwords. (hard)

Print milliseconds only (0 to 999)

I have worked a bit on the following code but still unable to print milliseconds (not all the millisecond from epoch time to user defined time).
Where am I lacking to print remaining milliseconds e.g. If seconds are 30 exactly, milliseconds should be only 0. Milliseconds should not be more than 999 obviously.
// Sets current date by default
Calendar ob = Calendar.getInstance();
// Sets user defined date with year, month, day of month respectively
Calendar dob = Calendar.getInstance();
dob.set(1990, 3, 25);
// Want to get milliseconds only (0 - 999)
long milli = dob.getTimeInMillis() - ( 60 * 60 * 24 * 30 * 12 * ( ob.get(Calendar.YEAR) - dob.get(Calendar.YEAR) ) );
System.out.println(milli);
Why not do
long justMillis = dob.getTimeInMillis() % 1000;
You want what's called the modulus operator, %. This basically finds the remainder of division.
long milli = dob.getTimeInMillis() % 1000;
System.out.println(milli % 1000);

Categories

Resources