Reputation: 2535
I am trying to calculate months elapsed since a particular date, the function works fine albeit it gives me a one months difference (Less than one month) if I put a date of today with a different year of the past.
Say for all dates the function works well, except:
If it is "2014-03-06" (YYYY,MM,DD) today and I process a date as "2006-03-06" to the function, the result is one month shorter, however if I use the same date tomorrow, the result is just fine. WOnder where I am going wrong. Below is the code:
public static int months(String d) {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = null;
try {
d1 = f.parse(d);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Date d2 = (getCurrentDate());
Date d2 = getCurrentDate();
Calendar c1 = Calendar.getInstance();
c1.setTime(d1);
Calendar c2 = Calendar.getInstance();
c2.setTime(d2);
int diff = 0;
if (c2.after(c1)) {
while (c2.after(c1)) {
c1.add(Calendar.MONTH, 1);
if (c2.after(c1)) {
diff++;
}
}
} else if (c2.before(c1)) {
while (c2.before(c1)) {
c1.add(Calendar.MONTH, -1);
if (c1.before(c2)) {
diff--;
}
}
}
System.out.println(diff);
return diff;
}
Please dont consider the static nature of functions, I have isolated this code in a different project for test purpose.
This is the value of c1 and c2:
java.util.GregorianCalendar[time=1141583400000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Kolkata",offset=19800000,dstSavings=0,useDaylight=false,transitions=6,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2006,MONTH=2,WEEK_OF_YEAR=10,WEEK_OF_MONTH=2,DAY_OF_MONTH=6,DAY_OF_YEAR=65,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=19800000,DST_OFFSET=0] and c2 is: java.util.GregorianCalendar[time=1394044200000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Kolkata",offset=19800000,dstSavings=0,useDaylight=false,transitions=6,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2014,MONTH=2,WEEK_OF_YEAR=10,WEEK_OF_MONTH=2,DAY_OF_MONTH=6,DAY_OF_YEAR=65,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=19800000,DST_OFFSET=0]
95
My bad here is the getCurrentDate():
public static Date getCurrentDate() {
String DateStr = new SimpleDateFormat("yyyy-MM-dd"/*,
current*/).format(Calendar.getInstance().getTime());
// String DateStr = formattedDate;
Date date = null;
try {
date = new SimpleDateFormat("yyyy-MM-dd"/*, current*/).parse(DateStr);
} catch (ParseException e) {
e.printStackTrace();
}
java.sql.Date dx = new java.sql.Date(date.getTime());
return dx;
}
Upvotes: 0
Views: 154
Reputation: 339382
As the correct answer by Deinlandel points out, this date-time work is much easier with the Joda-Time library.
Here's my take on some example code.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime dateTimeStart = new DateTime( "2006-03-06", timeZone );
DateTime dateTimeStop = new DateTime( "2014-03-06", timeZone );
int months = Months.monthsBetween( dateTimeStart, dateTimeStop ).getMonths();
Dump to console…
System.out.println( "dateTimeStart: " + dateTimeStart );
System.out.println( "dateTimeStop: " + dateTimeStop );
System.out.println( "months: " + months );
When run…
dateTimeStart: 2006-03-06T00:00:00.000+01:00
dateTimeStop: 2014-03-06T00:00:00.000+01:00
months: 96
Upvotes: 1
Reputation: 315
Change this:
Date d2 = getCurrentDate();
to this:
Calendar now = Calendar.getInstance();
Date d2 = now.getTime();
It returns 96 to me.
Edited---
If you're using your function getCurrentDate(), i suggest you replace it with this:
public static Date getCurrentDate() {
Calendar now = Calendar.getInstance();
Date d2 = now.getTime();
return d2
}
Upvotes: 1
Reputation: 1033
I know it's not always possible and desirable to add new dependencies to the project, but have you considered using JodaTime library for date/time calculations? It has much cleaner api, and it follows all calendar/timezone restricitions very strictly.
Here is example for your dates (date parsing from strings is omitted).
DateTime from = new DateTime(2006, 3, 6, 0, 0); //2006-03-06
DateTime to = new DateTime(2014, 3, 6, 0, 0); //2014-03-06
System.out.println(new Interval(from, to).toPeriod(PeriodType.months()));
It prints "P96M", that is, 96 months.
Note that this example uses default (system) timezone.
Upvotes: 2
Reputation: 347314
The comparisons of the Calendar
after
and before
also include the time information, this could be throwing of the calculation towards the end, cause the comparison to fail short...
Try adjusting the values to the day boundaries...for example...
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class TestMonths {
public static final String TEST1 = "2006-03-06";
public static final String TEST2 = "2014-03-06";
public static void main(String[] args) {
System.out.println(months(TEST2));
}
public static Date getCurrentDate() throws ParseException {
return new SimpleDateFormat("yyyy-MM-dd").parse(TEST1);
}
public static int months(String d) {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = null;
Date d2 = null;
try {
d1 = f.parse(d);
d2 = (getCurrentDate());
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Calendar c1 = Calendar.getInstance();
c1.setTime(d1);
Calendar c2 = Calendar.getInstance();
c2.setTime(d2);
int diff = 0;
if (c2.after(c1)) {
System.out.println("After");
setStartOfDay(c1);
setEndOfDay(c2);
while (c2.after(c1)) {
c1.add(Calendar.MONTH, 1);
if (c2.after(c1)) {
diff++;
}
}
} else if (c2.before(c1)) {
System.out.println("Before");
setStartOfDay(c2);
setEndOfDay(c1);
while (c2.before(c1)) {
c1.add(Calendar.MONTH, -1);
if (c2.before(c1)) {
diff--;
}
}
}
System.out.println(diff);
return diff;
}
public static void setStartOfDay(Calendar cal) {
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
}
public static void setEndOfDay(Calendar cal) {
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 99);
}
}
ps- I also corrected the "before" branch (where c2
is "before" c1
) as there was a logic error...
Upvotes: 2
Reputation: 3509
Check your getCurrentDate()
method. I have replaced with new Date()
and output is 96
as you said.
Upvotes: 1