Java實用經驗總結--日期、數字篇

 
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/022009-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.DATE1)的話,如果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;
    }
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章