Reputation: 1252
Please enlight me on this :
I'm simply trying to add 10 years to the current date then substract an expiration date from it to return the number of years:
public int getMaxYears() {
int max = 0;
Calendar ten_year_later = Calendar.getInstance();
ten_year_later.setTime(new Date());
ten_year_later.add(Calendar.YEAR, 10);
Calendar expiration = Calendar.getInstance();
expiration.setTime(expiration_date);
max = (int) (ten_year_later.getTimeInMillis() - expiration.getTimeInMillis())/(365 * 24 * 60 * 60 * 1000);
return max;
}
When I debug this, the calendar always stay at the current year.
Anyone ?
Upvotes: 8
Views: 23050
Reputation: 338181
Use modern java.time classes. Can be done in a one-liner (not that I recommend that).
Period
.between(
( ( GregorianCalendar) myCalendarExpiration ).toZonedDateTime().toLocalDate() ,
ZonedDateTime.now( ZoneId.of( "Asia/Kolkata" ) ).plusYears( 10 ).toLocalDate()
)
.getYears()
The modern approach uses the java.time classes that supplanted the legacy date-time classes such as Calendar
.
The usual concrete implementation of Calendar
is GregorianCalendar
. This is now replaced by ZonedDateTime
. You can convert back and forth by calling new methods on the old classes.
ZonedDateTime zdtExpiration = ( ( GregorianCalendar) myCal ).toZonedDateTime() ;
Get current moment.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdtNow = ZonedDateTime.now( z ) ;
Add ten years.
ZonedDateTime zdtLater = zdtNow.plusYears( 10 ) ;
Calculate elapsed time in years between the dates of those two moments.
Period p = Period.between(
zdtExpiration.toLocalDate() ,
zdtLater.toLocalDate()
) ;
Interrogate for the number of full years.
int yearsElapsed = p.getYears() ;
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
Upvotes: 1
Reputation: 1108557
Your calculation of max
is wrong. An int
cannot hold a year in millis.
Rather replace it by
max = ten_year_later.get(Calendar.YEAR) - expiration.get(Calendar.YEAR);
Or better, use JodaTime:
DateTime tenYearsLater = new DateTime().plusYears(10);
DateTime expiration = new DateTime(expiration_date.getTime());
Period period = new Period(expiration, tenYearsLater);
return period.getYears();
Upvotes: 6
Reputation: 2083
I've noted in a comment that you have an incorrect calculation for number of millis in a year (nevermind the int/long issue).
Since you have two calendars, each of which can keep a year, why don't you write your code like this (not compiled, so may contain typos):
Calendar cal1 = Calendar.newInstance(); // this will use current time
cal1.add(Calendar.YEAR, 10);
Calendar cal2 = Calendar.newInstance();
cal2.setDate(expiration);
return cal1.get(Calendar.YEAR) - cal2.get(Calendar.YEAR);
Assuming that's what you really want ...
Upvotes: 1
Reputation: 34313
The number of milliseconds in a year is well outside the range of an int, so both the int cast of ten_year_later.getTimeInMillis() - expiration.getTimeInMillis()
and the calculation 365 * 24 * 60 * 60 * 1000
will evaluate to incorrect values.
The ten_year_later
should be correct. There is no need to invoke computeFields as R. Bemrose wrote.
Upvotes: 0
Reputation: 326
Here's a simple example of what should work.
Calendar cal = new GregorianCalendar();
cal.setTime(new Date());
cal.add(Calendar.YEAR, yearsToAdd);
Date retDate = cal.getTime();
Just remember to use a long to get the time in milliseconds!
Upvotes: 5
Reputation: 68942
You have a problem with int / long conversion: 365 * 24 * 60 * 60 * 1000
Which evaluates to 31536000000 and therefore exceeds Integer.MAX_VALUE
2147483647
This works:
public static void main(String[] args) {
Calendar ten_year_later = Calendar.getInstance();
System.out.println( ten_year_later.getTime() );
ten_year_later.setTime(new Date());
ten_year_later.add(Calendar.YEAR, 10);
System.out.println( ten_year_later.getTime() );
Calendar expiration = Calendar.getInstance();
expiration.setTime(expiration.getTime());
long max = (ten_year_later.getTimeInMillis() - expiration.getTimeInMillis())/(365 * 24 * 60 * 60 * 1000L);
System.out.println( "max " + max );
}
Upvotes: 12
Reputation: 182762
Calendar is lazy, so it might not recalculate all the other fields until you ask for them. That's thrown me off in the debugger before. What happens if you System.out.println(ten_year_later);
?
Upvotes: 1