Java檢查日期格式是否正確

需求:由於系統有不少日期格式,因此日期驗證函數的輸入是一個日期字符串和一個格式字符串。格式字符串用的是Java定義的格式(參考地址)。正則表達式

剛開始寫時,以爲很簡單,直接就寫了下面的代碼。函數

public static boolean isDate(String dttm, String format) {
    boolean retValue = false;
    if (dttm != null) {
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        try {
            formatter.parse(dttm);
            retValue = true;
        } catch (ParseException e) {
        }
    }
    return retValue;

}測試

寫好以後,一測試,發現2012/12/43這種日期竟然也返回True,因而查資料,設置轉化時不進位formatter.setLenient(false);以後好用了,代碼爲code

public static boolean isDate(String dttm, String format) {
    boolean retValue = false;
    if (dttm != null) {
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        formatter.setLenient(false);
        try {
            formatter.parse(dttm);
            retValue = true;
        } catch (ParseException e) {
        }
    }
    return retValue;
}

寫到這裏,覺得萬事大吉了。但以後的測試卻發現,當日期有分隔符時,只會轉換前一部分,好比2012/12/30ABCD也會返回True。想了一下,以爲先轉爲日期型,再轉爲字符串,再比較二者是否相等,但立刻就否決了這個方案,由於客戶要求的是不嚴格的日期形式,如格式爲yyyy/MM/dd,輸入2012/1/2也須要驗證經過。而後考慮了一下,以爲先用正則表達式作一次驗證,而後再驗證是不是日期型。代碼以下orm

public static boolean isDate(String dttm, String format) {
    boolean retValue = false;

    if (dttm == null || dttm.isEmpty() || format == null || format.isEmpty()) {
        return retValue;
    }

    String regFormat = format;
    regFormat = regFormat.replaceAll("(^')|('$)", "");
    regFormat = regFormat.replaceAll("'([^'])", "$1");
    regFormat = regFormat.replace("''", "'");
    regFormat = regFormat.replace("\\", "\\\\");
    regFormat = regFormat.replaceAll("[MdHmsS]+", "\\d+");
    regFormat = regFormat.replaceAll("[y]+", "\\d{1,4}");
    if (!dttm.matches("^" + regFormat + "$")) {
        return false;
    }

    SimpleDateFormat formatter = new SimpleDateFormat(format);
    formatter.setLenient(false);
    try {
        formatter.parse(dttm);
        retValue = true;
    } catch (ParseException e) {
    }

    return retValue;
}

上面的代碼只對應了yMdHmsS,雖然對當時的系統已經足夠了,但仍是感受不太爽,以爲應該有一種通用的方法。因而查Java的API,發現parse方法還有一個帶參數的方法。理解了它的使用方法以後,把代碼改爲下面的樣子字符串

private static boolean isDate(String dttm, String format) {
    if (dttm == null || dttm.isEmpty() || format == null || format.isEmpty()) {
        return false;
    }

    DateFormat formatter = new SimpleDateFormat(format);
    formatter.setLenient(false);
    ParsePosition pos = new ParsePosition(0);
    Date date = formatter.parse(dttm, pos);

    if (date == null || pos.getErrorIndex() > 0) {
        return false;
    }

    if (pos.getIndex() != dttm.length()) {
        return false;
    }

    return true;
}

原本覺得這樣應該萬事大吉了,但以後的測試又發現兩個Bug。一個是,當輸入的日期沒有年份(需求是沒有輸入年份是默認當前年份)時,默認取的是1970年,這樣的話,若是當年是閏年的話,2/29號就驗證出錯了;另外一個是Java的日期和Oracle的日期大小不一樣,Oracle好像最大隻支持到9999年,而Java能夠有2萬多年。因此代碼又被改爲了下面的樣子get

private static boolean isDate(String dttm, String format) {
    if (dttm == null || dttm.isEmpty() || format == null || format.isEmpty()) {
        return false;
    }

    if (format.replaceAll("'.+?'", "").indexOf("y") < 0) {
        format += "/yyyy";
        DateFormat formatter = new SimpleDateFormat("/yyyy");
        dttm += formatter.format(new Date());
    }

    DateFormat formatter = new SimpleDateFormat(format);
    formatter.setLenient(false);
    ParsePosition pos = new ParsePosition(0);
    Date date = formatter.parse(dttm, pos);

    if (date == null || pos.getErrorIndex() > 0) {
        return false;
    }
    if (pos.getIndex() != dttm.length()) {
        return false;
    }

    if (formatter.getCalendar().get(Calendar.YEAR) > 9999) {
        return false;
    }

    return true;
}
相關文章
相關標籤/搜索