Reputation: 643
I'm working on creating a method to show the difference in time between two dates. To do this, I am using Calendar, and subtracting the dates to receive the remaining number available. However, for some reason, it's returning unexpected results. Here is my method in an extended Date
class:
public String getReadableTimeDifference(Date fromDate, boolean showMilliseconds) {
String[] result = new String[7];
Calendar calendar = Calendar.getInstance();
Calendar from = Calendar.getInstance();
calendar.setTime(this);
from.setTime(fromDate);
// The two dates are correct. using a polymorphic method getReadableTimeDifference(boolean),
// it supplies this method with the current date. "this" is always a date in the future.
// Let's say that "this" is a date 10 seconds in the future:
System.out.println(from.getTime());
System.out.println(this);
// Since it's 10 seconds in the future, it will print the same (2016):
System.out.println(calendar.get(Calendar.YEAR) + " " + from.get(Calendar.YEAR));
// It should subtract the from date (2016) from the existing date (2016)
calendar.add(Calendar.YEAR, -from.get(Calendar.YEAR));
calendar.add(Calendar.MONTH, -from.get(Calendar.MONTH));
calendar.add(Calendar.DATE, -from.get(Calendar.DATE));
calendar.add(Calendar.HOUR, -from.get(Calendar.HOUR));
calendar.add(Calendar.MINUTE, -from.get(Calendar.MINUTE));
calendar.add(Calendar.SECOND, -from.get(Calendar.SECOND));
calendar.add(Calendar.MILLISECOND, -from.get(Calendar.MILLISECOND));
// It should print "0" (because 2016-2016 = 0) but instead it prints 2.
System.out.println(calendar.get(Calendar.YEAR));
int years = Math.abs(calendar.get(Calendar.YEAR));
int months = Math.abs(calendar.get(Calendar.MONTH));
int days = Math.abs(calendar.get(Calendar.DATE));
int hours = Math.abs(calendar.get(Calendar.HOUR));
int minutes = Math.abs(calendar.get(Calendar.MINUTE));
int seconds = Math.abs(calendar.get(Calendar.SECOND));
int milliseconds = Math.abs(calendar.get(Calendar.MILLISECOND));
if (years > 0) {
result[0] = Utilities.prettyNumerate("year", years);
}
if (months > 0) {
result[1] = Utilities.prettyNumerate("month", months);
}
if (days > 0) {
result[2] = Utilities.prettyNumerate("day", days);
}
if (hours > 0) {
result[3] = Utilities.prettyNumerate("hour", hours);
}
if (minutes > 0) {
result[4] = Utilities.prettyNumerate("minute", minutes);
}
if (seconds > 0) {
result[5] = Utilities.prettyNumerate("second", seconds);
}
if (milliseconds > 0 && showMilliseconds) {
result[6] = Utilities.prettyNumerate("millisecond", milliseconds);
}
return Utilities.join(Utilities.clean(result), ", ", " and ");
}
prettyNumerate
takes a number and appends an "s" to the end of the supplied string if it's over 1, under -1 or 0. clean
cleans an array of any null or empty elements. join
join's an array by a delimiter, and a final delimiter for the last element. The expected outcome should be:
10 seconds
But instead it's:
2 years, 11 months, 31 days and 10 seconds
Nothing else is being manipulated within this custom date. When I instantiate this custom date, after any custom code is completed I print out this.getTime()
and it prints out the correct time in milliseconds, which is 10 seconds into the future as it should be.
Upvotes: 0
Views: 98
Reputation: 556
The year field in Calendar object of Java is relative to the era. By setting the year to something less or equal to 0 the calendar automatically corrects this by switching the era (from AD to BC or from BC to AD). This behaviour is better known from the other fields. For example, if you set the month to something negative, the year gets decremented accordingly.
Those corrections aren't made individually but rather they are made all at once, usually when you call getTime() to read out the resulting date.
Therefore, if you subtract year 2016 from a date in 2016, it automatically gets corrected to 1st century BC. When you do more subtractions, the time actually reaches 2nd century BC.
As suggested in some comments, you will be better off using Joda time for your usecase.
Upvotes: 1