java 日期只计算年月日大小_Java按自然月计算两个日期相差的年月日?
曾經我以為計算兩個日期之差很簡單,在給我的團隊成員分配任務時,也覺得就是調用一個方法的問題,可是當我發現結果老是不對時,才發現原來JDK 提供的API中根本沒有這樣的方法,我也很惱火,也怪不得不少牛人在博客里怒斥Java標準庫中對日期的處理晦澀不堪的現狀,想這樣的功能提供也是理所應當的,也就說明Date,Calendar中提供的日期處理的功能不夠強大,因為已經有開源(Joda,某個知名的Java開源類庫,在時間日期的處理上相比Java標準庫更加強大且易用,IBM的日期類庫中提供了強大的功能),各大論壇中對這個問題爭論很多,可是很多都是考慮的比較簡單,每個月按30天計算,可能你會說,計算的這么精確嗎?答案是在一定的場合下是非常有必要的,在銀行,圖書館過期圖書計費,網絡流量計費等,都是按照自然月來計算的,需要考慮的因素很多,而不是簡單的30天,我現在需要的場合是Baby Care這款軟件中,要計算Baby的年齡,就是xx years,xx months,xx days,因為很多人需要用這個看看小孩是否滿月,是否周歲等,開始為了簡單,我們按30天每月,后來有人反饋,計算方法不對,只好讓用戶選擇,是每月按30天計算,還是按自然月計算。
按每月30天計算,論壇中常討論的方法,,并且似乎也是沒有問題的,但是往往計算的結果有時會相差一天:
public long diffValue(Date date1, Date date2)
{
//return date1.getTime() / (24*60*60*1000) - date2.getTime() / (24*60*60*1000);
return (date2.getTime() - date1.getTime() )/ 86400000; //用立即數,減少乘法計算的開銷
}
下面是正確的解法:
問題的關鍵是過濾掉時分秒,保留日期部分。干的活象低通濾波器,濾掉高頻雜波,保留低頻信號,/86400000,就是把時分秒全忽略掉了。
解法1:
public long differ(Date date1, Date date2)
{
//return date1.getTime() / (24*60*60*1000) - date2.getTime() / (24*60*60*1000);
return date2.getTime() / 86400000 - date1.getTime() / 86400000; //用立即數,減少乘法計算的開銷
}
解法2:
把date1,date2都設置為同樣的時間,我曾經設置date1為00:00:00,date2為23:59:59秒,在非常情況下,1S之差也會導致計算的天數少1.
private int daysBetween(Date now, Date returnDate) {
Calendar cNow = Calendar.getInstance();
Calendar cReturnDate = Calendar.getInstance();
cNow.setTime(now);
cReturnDate.setTime(returnDate);
setTimeToMidnight(cNow);
setTimeToMidnight(cReturnDate);
long todayMs = cNow.getTimeInMillis();
long returnMs = cReturnDate.getTimeInMillis();
long intervalMs = todayMs - returnMs;
return millisecondsToDays(intervalMs);
}
private int millisecondsToDays(long intervalMs) {
return (int) (intervalMs / (1000 * 86400));
}
private void setTimeToMidnight(Calendar calendar) {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
}
解法3:
SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date= myFormatter.parse("2003-05-1");
java.util.Date mydate= myFormatter.parse("1899-12-30");
long day=(date.getTime()-mydate.getTime())/(24*60*60*1000);
out.println(day);
上面的解法思想都一樣,都是忽略的時分秒,相比之下,第一種方法最為簡單,可是這些都是每月按30天計算的,自然月計算的方法系統API中沒有,總不至于為了使用這個方法,去引用開源的庫吧,但是這個問題的處理邏輯也是很復雜的,要考慮的因素很多,往往測試的時候,發現某種特例計算的結果不正確,煞為惱火,Java真不給力~~
基本上花了一下午的時間,去分析,然后畫了流程圖,寫成代碼,可能水平有限,方法雖然笨拙,但是還是能用的,如有不正確的地方,歡迎大家指正,也期待有更加簡單巧妙的方法。
相應代碼:
public static int[] getNeturalAge(Calendar calendarBirth,Calendar calendarNow) {
int diffYears = 0, diffMonths, diffDays;
int dayOfBirth = calendarBirth.get(Calendar.DAY_OF_MONTH);
int dayOfNow = calendarNow.get(Calendar.DAY_OF_MONTH);
if (dayOfBirth <= dayOfNow) {
diffMonths = getMonthsOfAge(calendarBirth, calendarNow);
diffDays = dayOfNow - dayOfBirth;
if (diffMonths == 0)
diffDays++;
} else {
if (isEndOfMonth(calendarBirth)) {
if (isEndOfMonth(calendarNow)) {
diffMonths = getMonthsOfAge(calendarBirth, calendarNow);
diffDays = 0;
} else {
calendarNow.add(Calendar.MONTH, -1);
diffMonths = getMonthsOfAge(calendarBirth, calendarNow);
diffDays = dayOfNow + 1;
}
} else {
if (isEndOfMonth(calendarNow)) {
diffMonths = getMonthsOfAge(calendarBirth, calendarNow);
diffDays = 0;
} else {
calendarNow.add(Calendar.MONTH, -1);// 上個月
diffMonths = getMonthsOfAge(calendarBirth, calendarNow);
// 獲取上個月最大的一天
int maxDayOfLastMonth = calendarNow .getActualMaximum(Calendar.DAY_OF_MONTH);
if (maxDayOfLastMonth > dayOfBirth) {
diffDays = maxDayOfLastMonth - dayOfBirth + dayOfNow;
} else {
diffDays = dayOfNow;
}
}
}
}
// 計算月份時,沒有考慮年
diffYears = diffMonths / 12;
diffMonths = diffMonths % 12;
return new int[] { diffYears, diffMonths, diffDays };
}
/**
* 獲取兩個日歷的月份之差
*
* @param calendarBirth
* @param calendarNow
* @return
*/
public static int getMonthsOfAge(Calendar calendarBirth,
Calendar calendarNow) {
return (calendarNow.get(Calendar.YEAR) - calendarBirth
.get(Calendar.YEAR))* 12+ calendarNow.get(Calendar.MONTH)
- calendarBirth.get(Calendar.MONTH);
}
/**
* 判斷這一天是否是月底
*
* @param calendar
* @return
*/
public static boolean isEndOfMonth(Calendar calendar) {
int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
if (dayOfMonth == calendar.getActualMaximum(Calendar.DAY_OF_MONTH))
return true;
return false;
}
如果你有更好的方法,歡迎探討:-)
總結
以上是生活随笔為你收集整理的java 日期只计算年月日大小_Java按自然月计算两个日期相差的年月日?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux工作原理fiq,读Kernel
- 下一篇: java写一个服务定时采集数据_java