How NOT to do it
// give me the date X days from the day represented by cal
public static String getOffsetDate(Calendar cal, int daysOffset){
cal.add(Calendar.DATE, daysOffset);
return dateFormat.format(cal.getTime());
}
This function appears to work until you call it a second and third time, and find out (like I did) that the new calendar value is being retained each time, and so increasing the daysOffset incrementally results in dates that are additively further out:
Today :2011-01-15 1 days ago : 2011-01-14 2 days ago : 2011-01-12 3 days ago : 2011-01-09 4 days ago : 2011-01-05 5 days ago : 2010-12-31 // wait. what?!
Apparently the Calendar.getInstance() gives you a singleton. Try passing it around to other methods, expecting it to make a new instance of itself and you'll run into problems. I found this to be extremely annoying and non-intuitive, and the Java Doc does not warn you about this, either.
Solution
So what's the solution? You have to create a new instance, or clone() the instance of the calendar before making the calculation (see sample code below).package com.test.calendar;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class CalendarTestDaysAgo {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
/**
* @param args
*/
public static void main(String[] args) {
Calendar cal = Calendar.getInstance(); // today
// set to January 15
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 15);
System.out.print("Today :"+getOffsetDate(cal,0) + "\n");
for (int d = 1; d < 32; d++){
System.out.print(d + " days ago: " + getOffsetDate(cal, d * -1) + "\n");
}
}
// give me the date X days hence from the day represented by cal
public static String getOffsetDate(Calendar cal, int daysOffset){
// this clone() call is required
// otherwise subsequent changes are additive
Calendar newCal = (Calendar) cal.clone();
newCal.add(Calendar.DATE, daysOffset);
return dateFormat.format(newCal.getTime());
}
}
Results in:
Today :2011-01-15 1 days ago : 2011-01-14 2 days ago : 2011-01-13 3 days ago : 2011-01-12 4 days ago : 2011-01-11 5 days ago : 2011-01-10 // that's better. ...
"Apparently the Calendar.getInstance() gives you a singleton" are you of it ? I don't think it does.
ReplyDeleteJust a note: Calendar.getInstance() doesn't return a singleton instance. Actually it's a factory method that returns a new instance each time it's called.
ReplyDeleteHowever, Calendars are mutable, which is considered by many as a design flaw of the API, because a single method can change the content and break the program. All other basic types in java are immutable for this very reason.
By the way, the solution is correct.