Java按自然月計算兩個日期相差的年月日?

來源:互聯網
上載者:User

曾經我以為計算兩個日期之差很簡單,在給我的團隊成員分配任務時,也覺得就是調用一個方法的問題,可是當我發現結果老是不對時,才發現原來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:

這篇部落格對這個問題分析的比較透徹:http://blog.csdn.net/solomonxu/archive/2007/04/27/1587237.aspx

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:

http://blog.csdn.net/rmartin/archive/2006/12/22/1452867.aspx;http://butunclebob.com/ArticleS.UncleBob.JavaDates;

把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;      } 

如果你有更好的方法,歡迎探討:-)

本文出自 “超越夢想” 部落格,請務必保留此出處http://breezy.blog.51cto.com/2400264/451353

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.