
Java實用經驗總結--日期、數字篇 1. 日期部分 對于像日期、時間和錢這樣的對象來說,不同的國家、地區都有不同的顯示格式。即便是同一地區,也可能存在差異。但是在不考慮國家化,時間格式相對固定的情形下,對于時間的處理還是相對比較簡單的。在我最近所作的一個小程序里面,遇到了一些與日期有關的且不考慮國際化和復雜格式的問題。例如如何求兩個日期所差的天數,所差的月數;將日期類轉化為規定格式的字符串,將規定格式的日期字符串轉成相應的日期類等等。下面我就以源碼的形式逐一介紹上面提到的問題,需要注意的是這些代碼都源于我做的一個名為DateUtil的類,其中獨立的變量都是其中的成員變量,函數都是其成員函數: 1.1.成員變量簡介: 要想對日期進行格式化首先就需要一個DateFormat類的實例,如果沒有特殊需求的話,SimpleDateFormat類就是一個不錯的選擇,它可以將日期類格式化為在其構造函數中指定的日期格式。例如,如果我們想要將日期格式化為類似于2007-07-25這樣的格式,我們就可以如下定義: /**以yyyy-MM-dd的形式顯示格式 **/ SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat sFullFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 這里需要注意的是指定的日期格式一定要是”yyyy-MM-dd”,而不能是”YYYY-MM-DD”,否則的就不能正常顯示。對于這個問題我沒有深究,如果有對這個問題有研究的朋友歡迎留言。 下面的兩個成員變量分別是日期分隔符字符串和字符串分隔器,專門用來解析字符串格式的日期。 /** *程序中主要的日期分隔符為"-"和"/",且日期序列為“年/月/日”型,其內容缺一不可 * 例如:09/02/02或2009-02-02 **/ publicstaticfinal String DATE_SEPARATOR ="-/"; /**作日期分析之用*/ static StringTokenizer sToken; 1.2.取得兩個日期之間所差天數的方法 鑒于java.util.Date類的絕大多數方法都不建議使用了,所以我也就不能夠利用Date里面方便的getYear(),getMonth(),getDay()方法來計算日期差了—現在的JRE都可以自動升級,誰知道哪天SUN突然把Date這些API去掉了,那我就欲哭無淚了。不過話又說回來就算是能夠使用這些方法,我們似乎也不太好算,因為每個月的日期數都不一樣,如果單純用兩個日期的年月日信息來計算日期差還真是有些麻煩。基于以上兩點原因,我在我的程序里采用了GregorianCalendar做為日期計算的主力軍。這個類有一些很實用的方法,如get(int),這個方法可以獲得當前日期類的各項日期指標。比如我們有一個日期類名為gcDate,要獲取它所在的年,月,日,至需要這么做:gcDate.get(Calendar.YEAR), gcDate.get(Calendar.MONTH)以及gcDate.get(Calendar.DATE)。不過由于使用這種方法獲得的日期和月份都是日期類所指定的年份的,所以如果我們知道兩個日期在同一年份的話才能使用gcDate1.get(Calendar.DATE)- gcDate2.get(Calendar.DATE)來獲得日期差,否則就不能這么做。 所以如果想要獲得不在同一年份的日期差的話就需要用到另一個有用的方法:GregorianCalendar.add(int, int),這個方法可以讓我們在日期類指定的日期指標(如年,月,日等)上加上一個數字,這個數字可以是正數也可以為負數。 其中第一個參數指定所要增加的指標,第二個參數指定增加的數量。例如我們調用gcDate.add(Calendar.DATE,1)的話,如果gcDate原來代表的時間為2007-07-24,那么調用之后就變成2007-07-25了。于是我們就可以這樣計算日期差:讓日期比較小的那個日期用add函數逐漸“逼近”那個較大的日期,直到兩個日期完全相等為止。計數器中包含的數量即為兩個日期的差值。 下面我給出了多個的計算日期差的方法,主要包含兩個版本,一個版本參數為格式化字符串,另一個版本參數為GregorianCalendar。功能包括計算“今天與未來的某一天之間的日期差”和“給定兩個日期的日期差”。主要的計算集中在最后一個daysBetween函數上,該函數接受兩個GregorianCalendar類作為參數,并可以計算出兩個日期之間的日期差,如果用戶給出的較大的日期和較小的日期順序顛倒的話,該函數會返回一個負數值。 /** *返回未來的某一天和今天所差的日期數 *注意,這里要clone一個新的日期以免對原始日期類造成的修改。 *而在daysBetween(GregorianCalendarpFormer,GregorianCalendarpLatter)就 *直接處理而不進行clone動作,因為這里已經做了:) **/ publicstaticint daysBetween(GregorianCalendar pFurtherDay){ GregorianCalendar vToday = new GregorianCalendar(); GregorianCalendar vFurtherDay = (GregorianCalendar) pFurtherDay.clone(); return daysBetween(vToday,vFurtherDay); } /**上面函數的String版本 **/ publicstaticint daysBetween(String pFurtherDayStr){ GregorianCalendar vFurtherDay = DateUtil.parse2Cal(pFurtherDayStr); GregorianCalendar vToday = new GregorianCalendar(); return daysBetween(vToday,vFurtherDay); } /**返回較晚的時間(latter)與較早的時間(former)所差的天數**/ publicstaticint daysBetween(String pFormerStr,String pLatterStr){ GregorianCalendar pFormer = DateUtil.parse2Cal(pFormerStr); GregorianCalendar pLatter = DateUtil.parse2Cal(pLatterStr); return daysBetween(pFormer,pLatter); } /**返回較晚的時間(latter)與較早的時間(former)所差的天數**/ publicstaticint daysBetween(GregorianCalendar pFormer,GregorianCalendar pLatter){ GregorianCalendar vFormer = pFormer,vLatter = pLatter; boolean vPositive = true; if( pFormer.before(pLatter) ){ vFormer = pFormer; vLatter = pLatter; }else{ vFormer = pLatter; vLatter = pFormer; vPositive = false; } vFormer.set(Calendar.MILLISECOND,0); vFormer.set(Calendar.SECOND,0); vFormer.set(Calendar.MINUTE,0); vFormer.set(Calendar.HOUR_OF_DAY,0); vLatter.set(Calendar.MILLISECOND,0); vLatter.set(Calendar.SECOND,0); vLatter.set(Calendar.MINUTE,0); vLatter.set(Calendar.HOUR_OF_DAY,0); int vCounter = 0; while(vFormer.before(vLatter)){ vFormer.add(Calendar.DATE, 1); vCounter++; } if( vPositive) return vCounter; else return -vCounter; } 1.3.兩個日期的月份差 獲得兩個日期的月份差的方法與獲得日期差基本一致。但需要注意的是,計算月份差不能簡單用before()來進行計算。還需要考慮到他們的年份及月份是否同時相等,只有在這種情況下,才能獲得月份差的正確數值。下面同樣給出了月份差的兩個版本的多個函數,與日期差基本一致,這里就不再贅述。 /** *給定兩個時間相差的月數 */ //本月和未來一個月的月份差 publicstaticint monthsBetween(GregorianCalendar pFurtherMonth){ GregorianCalendar vToday = new GregorianCalendar(); GregorianCalendar vFurtherMonth = (GregorianCalendar) pFurtherMonth.clone(); return monthsBetween(vToday,vFurtherMonth); } /**給定月分和本月的月份差**/ publicstaticint monthsBetween(String pFurtherMonth){ GregorianCalendar vToday = new GregorianCalendar(); GregorianCalendar vFurtherMonth = DateUtil.parse2Cal(pFurtherMonth); return monthsBetween(vToday,vFurtherMonth); } /**給定兩個時間相差的月數,String版**/ publicstaticint monthsBetween(String pFormerStr,String pLatterStr){ GregorianCalendar vFormer = DateUtil.parse2Cal(pFormerStr); GregorianCalendar vLatter = DateUtil.parse2Cal(pLatterStr); return monthsBetween(vFormer,vLatter); } publicstaticint monthsBetween(GregorianCalendar pFormer,GregorianCalendar pLatter){ GregorianCalendar vFormer = pFormer,vLatter = pLatter; boolean vPositive = true; if( pFormer.before(pLatter) ){ vFormer = pFormer; vLatter = pLatter; }else{ vFormer = pLatter; vLatter = pFormer; vPositive = false; } int vCounter = 0; while(vFormer.get(vFormer.YEAR) != vLatter.get(vLatter.YEAR) || vFormer.get(vFormer.MONTH) != vLatter.get(vLatter.MONTH)){ vFormer.add(Calendar.MONTH, 1); vCounter++; } if( vPositive) return vCounter; else return -vCounter; } 1.4.格式轉換 將日期類轉換成制定格式的字符串只需要調用DateFormat.format()即可。而反過來就比較麻煩,我們需要對字符串進行分析,找出其年,月,日的值分別為何,然后再用GregorianCalendar(vYear,vMonth,vDayOfMonth)構建一個新的日期類。 /** 將日期變為字符串格式 **/ publicstatic String format(GregorianCalendar pCal){ returnsDateFormat.format(pCal.getTime()); } publicstatic String format(Date pDate){ returnsDateFormat.format(pDate); } publicstatic String fullFormat(Date pDate){ returnsFullFormat.format(pDate); } /**將字符串格式的日期轉換為Calender**/ publicstatic GregorianCalendar parse2Cal(String pDateStr){ sToken = new StringTokenizer(pDateStr,DATE_SEPARATOR); int vYear = Integer.parseInt(sToken.nextToken()); //GregorianCalendar的月份是從0開始算起的,變態!! int vMonth = Integer.parseInt(sToken.nextToken())-1; int vDayOfMonth = Integer.parseInt(sToken.nextToken()); returnnew GregorianCalendar(vYear,vMonth,vDayOfMonth); } /**將字符串類型的日期(yyyy-MM-dd)轉換成Date**/ publicstatic Date parse2Date(String pDate){ try { returnsDateFormat.parse(pDate); }catch(ParseException ex) { returnnull; } } 1.5.其他 這部分主要是一些常用方法的包裝,包括獲得今天是本月的第幾天,本月是本年的第幾個月,獲得給定字符串日期的月份數,以及獲得下面這個月份區間[本月,本月+pZoneSize]里的月份列表。即如果本月為6月,pZoneSize=6,則獲得的月份列表應該為{6,7,8,9,10,11,12} /**返回今天是本月的第幾天**/ publicstaticint dayOfMonthOfToday(){ GregorianCalendar vTodayCal = new GregorianCalendar(); return vTodayCal.get(vTodayCal.DAY_OF_MONTH); } /**返回本月是本年的第幾個月**/ publicstaticint monthOfYear(){ GregorianCalendar vTodayCal = new GregorianCalendar(); return vTodayCal.get(vTodayCal.MONTH)+1; } //返回給定日期的月份 publicstatic String getMonth(String pFormattedDate){ StringTokenizer vSt = new StringTokenizer(pFormattedDate,"-"); vSt.nextToken();//跳過年份 int val = Integer.parseInt(vSt.nextToken()); return val+""; } /**獲得從本月開始到本月+pZoneSize區間內的月數**/ publicstatic String[] monthList(int pZoneSize){ String[] vMonthList = new String[pZoneSize]; GregorianCalendar vTodayCal = new GregorianCalendar(); for(int i = 0; i < pZoneSize; i++){ vMonthList[i] = String.valueOf(vTodayCal.get(vTodayCal.MONTH)+1); vTodayCal.roll(vTodayCal.MONTH,true); } return vMonthList; } 2. 數字部分: 這一部分我的工作比較簡單,首先是格式化給定的Double變量,讓其只顯示兩位小數。其次是由于我所做的程序付款額都是以萬作為單位的,所以在必要的時候將其轉為以萬為單位的,帶有兩位小數的數字。由于比較簡單,這里就不多說,各位看代碼就好: /**僅顯示小數點后兩位的Formater**/ publicstatic DecimalFormat formatter = new DecimalFormat("####.##"); /**將給定的數字變成小數點后兩位的字符串**/ publicstatic String format(double pSrcVal){ returnformatter.format(pSrcVal); } /**將原始數據除以10000所得的結果**/ publicstatic String fromat2Myriad(double pSrcVal){ returnformatter.format(pSrcVal/10000.0); } /**將原始數據除以10000所得的結果**/ publicstatic String fromat2Myriad(String pSrcVal){ returnformatter.format(Double.parseDouble(pSrcVal)/10000.0); } /**將給定的數字保留兩位小數返回**/ publicstaticdouble format2Double(double pSrcVal){ return (double)Math.round(pSrcVal*100)/100.0; }
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
