Java檢查日期字符串是否合法的方法總結(jié)
WHY
后端接口在接收數(shù)據(jù)的時候,都需要進行檢查。檢查全部通過后,才能夠執(zhí)行業(yè)務(wù)邏輯。對于時間格式,我們一般需要檢查這么幾方面:
- 字符串格式是否正確,比如格式是不是yyyy-MM-dd
- 時間在合法范圍內(nèi),比如我們需要限定在一個月內(nèi)的時間
- 字符串可以解析為正常的時間,比如 2 月 30 號就不是正常時間
對于時間格式的判斷,我們可以通過正則表達式來檢查。不過考慮到正則表達式的性能、輸入數(shù)據(jù)的復(fù)雜性,一般能用別的方式,就不選正則表達式。我們還是選擇一種更加通用、更加高效的檢查方式。
首先,定義時間校驗器的接口:
public interface DateValidator { boolean isValid(String dateStr); }
接口方法接收一個字符串,返回布爾類型,表示字符串是否是合法的時間格式。
HOW
接下來就是通過不同方式實現(xiàn)DateValidator。
1.使用 DateFormat 檢查
Java 提供了格式化和解析時間的工具:DateFormat
抽象類和SimpleDataFormat
實現(xiàn)類。我們借此實現(xiàn)時間校驗器:
public?class?DateValidatorUsingDateFormat?implements?DateValidator?{ ????private?final?String?dateFormat; ????public?DateValidatorUsingDateFormat(String?dateFormat)?{ ????????this.dateFormat?=?dateFormat; ????} ????@Override ????public?boolean?isValid(String?dateStr)?{ ????????final?DateFormat?sdf?=?new?SimpleDateFormat(this.dateFormat); ????????sdf.setLenient(false); ????????try?{ ????????????sdf.parse(dateStr); ????????}?catch?(ParseException?e)?{ ????????????return?false; ????????} ????????return?true; ????} }
這里需要注意一下,DateFormat
和SimpleDataFormat
是非線程安全的,所以每次方法調(diào)用時,都需要新建實例。
我們通過單元測試驗證下:
class?DateValidatorUsingDateFormatTest?{ ????@Test ????void?isValid()?{ ????????final?DateValidator?validator?=?new?DateValidatorUsingDateFormat("yyyy-MM-dd"); ????????Assertions.assertTrue(validator.isValid("2021-02-28")); ????????Assertions.assertFalse(validator.isValid("2021-02-30")); ????} }
在 Java8 之前,一般都是用這種方式來驗證。Java8 之后,我們有了更多的選擇。
2.使用 LocalDate 檢查
Java8 引入了更加好用日期和時間 API(想要了解更多內(nèi)容,請移步參看 Java8 中的時間類及常用 API)。其中包括LocalDate
類,是一個不可變且線程安全的時間類。
LocalDate
提供了兩個靜態(tài)方法,用來解析時間。這兩個方法內(nèi)部都是使用java.time.format.DateTimeFormatter
來處理數(shù)據(jù):
//?使用?DateTimeFormatter.ISO_LOCAL_DATE?處理數(shù)據(jù) public?static?LocalDate?parse(CharSequence?text)?{ ????return?parse(text,?DateTimeFormatter.ISO_LOCAL_DATE); } //?使用提供的?DateTimeFormatter?處理數(shù)據(jù) public?static?LocalDate?parse(CharSequence?text,?DateTimeFormatter?formatter)?{ ????????Objects.requireNonNull(formatter,?"formatter"); ????return?formatter.parse(text,?LocalDate::from); }
通過LocalDate
的parse
方法實現(xiàn)我們的校驗器:
public?class?DateValidatorUsingLocalDate?implements?DateValidator?{ ????private?final?DateTimeFormatter?dateFormatter; ????public?DateValidatorUsingLocalDate(DateTimeFormatter?dateFormatter)?{ ????????this.dateFormatter?=?dateFormatter; ????} ????@Override ????public?boolean?isValid(String?dateStr)?{ ????????try?{ ????????????LocalDate.parse(dateStr,?this.dateFormatter); ????????}?catch?(DateTimeParseException?e)?{ ????????????return?false; ????????} ????????return?true; ????} }
java.time.format.DateTimeFormatter
類是不可變的,也就是天然的線程安全,我們可以在不同線程使用同一個校驗器實例。
我們通過單元測試驗證下:
class?DateValidatorUsingLocalDateTest?{ ????@Test ????void?isValid()?{ ????????final?DateTimeFormatter?dateFormatter?=?DateTimeFormatter.ISO_LOCAL_DATE; ????????final?DateValidator?validator?=?new?DateValidatorUsingLocalDate(dateFormatter); ????????Assertions.assertTrue(validator.isValid("2021-02-28")); ????????Assertions.assertFalse(validator.isValid("2021-02-30")); ????} }
既然LocalDate#parse
是通過DateTimeFormatter
實現(xiàn)的,那我們也可以直接使用DateTimeFormatter
。
3.使用 DateTimeFormatter 檢查
DateTimeFormatter
解析文本總共分兩步。第一步,根據(jù)配置將文本解析為日期和時間字段;第二步,用解析后的字段創(chuàng)建日期和時間對象。
實現(xiàn)驗證器:
public?class?DateValidatorUsingDateTimeFormatter?implements?DateValidator?{ ????private?final?DateTimeFormatter?dateFormatter; ????public?DateValidatorUsingDateTimeFormatter(DateTimeFormatter?dateFormatter)?{ ????????this.dateFormatter?=?dateFormatter; ????} ????@Override ????public?boolean?isValid(String?dateStr)?{ ????????try?{ ????????????this.dateFormatter.parse(dateStr); ????????}?catch?(DateTimeParseException?e)?{ ????????????return?false; ????????} ????????return?true; ????} }
通過單元測試驗證:
class?DateValidatorUsingDateTimeFormatterTest?{ ????private?static?final?DateTimeFormatter?DATE_FORMATTER?=?DateTimeFormatter.ofPattern("uuuu-MM-dd",?Locale.CHINA); ????@Test ????void?isValid()?{ ????????final?DateTimeFormatter?dateFormatter?=?DATE_FORMATTER.withResolverStyle(ResolverStyle.STRICT); ????????final?DateValidator?validator?=?new?DateValidatorUsingDateTimeFormatter(dateFormatter); ????????Assertions.assertTrue(validator.isValid("2021-02-28")); ????????Assertions.assertFalse(validator.isValid("2021-02-30")); ????} }
可以看到,我們指定了轉(zhuǎn)換模式是ResolverStyle.STRICT
,這個類型是說明解析模式。共有三種:
- STRICT:嚴格模式,日期、時間必須完全正確。
- SMART:智能模式,針對日可以自動調(diào)整。月的范圍在 1 到 12,日的范圍在 1 到 31。比如輸入是 2 月 30 號,當(dāng)年 2 月只有 28 天,返回的日期就是 2 月 28 日。
- LENIENT:寬松模式,主要針對月和日,會自動后延。結(jié)果類似于
LocalData#plusDays
或者LocalDate#plusMonths
。
我們通過例子看下區(qū)別:
class?DateValidatorUsingDateTimeFormatterTest?{ ????private?static?final?DateTimeFormatter?DATE_FORMATTER?=?DateTimeFormatter.ofPattern("uuuu-MM-dd",?Locale.CHINA); ????@Test ????void?testResolverStyle()?{ ????????Assertions.assertEquals(LocalDate.of(2021,?2,28),?parseDate("2021-02-28",?ResolverStyle.STRICT)); ????????Assertions.assertNull(parseDate("2021-02-29",?ResolverStyle.STRICT)); ????????Assertions.assertEquals(LocalDate.of(2021,?2,28),?parseDate("2021-02-28",?ResolverStyle.STRICT)); ????????Assertions.assertNull(parseDate("2021-13-28",?ResolverStyle.STRICT)); ????????Assertions.assertEquals(LocalDate.of(2021,?2,28),?parseDate("2021-02-28",?ResolverStyle.SMART)); ????????Assertions.assertEquals(LocalDate.of(2021,?2,28),?parseDate("2021-02-29",?ResolverStyle.SMART)); ????????Assertions.assertNull(parseDate("2021-13-28",?ResolverStyle.SMART)); ????????Assertions.assertNull(parseDate("2021-13-29",?ResolverStyle.SMART)); ????????Assertions.assertEquals(LocalDate.of(2021,?2,28),?parseDate("2021-02-28",?ResolverStyle.LENIENT)); ????????Assertions.assertEquals(LocalDate.of(2021,?3,1),?parseDate("2021-02-29",?ResolverStyle.LENIENT)); ????????Assertions.assertEquals(LocalDate.of(2022,?1,28),?parseDate("2021-13-28",?ResolverStyle.LENIENT)); ????????Assertions.assertEquals(LocalDate.of(2022,?2,2),?parseDate("2021-13-33",?ResolverStyle.LENIENT)); ????} ????private?static?LocalDate?parseDate(String?dateString,?ResolverStyle?resolverStyle)?{ ????????try?{ ????????????return?LocalDate.parse(dateString,?DATE_FORMATTER.withResolverStyle(resolverStyle)); ????????}?catch?(DateTimeParseException?e)?{ ????????????return?null; ????????} ????} }
從例子可以看出,ResolverStyle.STRICT
是嚴格控制,用來做時間校驗比較合適;ResolverStyle.LENIENT
可以最大程度將字符串轉(zhuǎn)化為時間對象,在合理范圍內(nèi)可以隨便玩;ResolverStyle.SMART
名為智能,但智力有限,兩不沾邊,優(yōu)勢不夠明顯。JDK 提供的DateTimeFormatter
實現(xiàn),都是ResolverStyle.STRICT
模式。
說了 JDK 自帶的實現(xiàn),接下來說說第三方組件的實現(xiàn)方式。
4.使用 Apache 出品的 commons-validator 檢查
Apache Commons 項目提供了一個校驗器框架,包含多種校驗規(guī)則,包括日期、時間、數(shù)字、貨幣、IP 地址、郵箱、URL 地址等。本文主要說檢查時間,所以重點看看GenericValidator
類提供的isDate
方法:
public?class?GenericValidator?implements?Serializable?{ ????//?其他方法 ????public?static?boolean?isDate(String?value,?Locale?locale)?{ ????????return?DateValidator.getInstance().isValid(value,?locale); ????} ????public?static?boolean?isDate(String?value,?String?datePattern,?boolean?strict)?{ ????????return?org.apache.commons.validator.DateValidator.getInstance().isValid(value,?datePattern,?strict); ????} }
先引入依賴:
<dependency> ????<groupId>commons-validator</groupId> ????<artifactId>commons-validator</artifactId> ????<version>1.7</version> </dependency>
實現(xiàn)驗證器:
public?class?DateValidatorUsingCommonsValidator?implements?DateValidator?{ ????private?final?String?dateFormat; ????public?DateValidatorUsingCommonsValidator(String?dateFormat)?{ ????????this.dateFormat?=?dateFormat; ????} ????@Override ????public?boolean?isValid(String?dateStr)?{ ????????return?GenericValidator.isDate(dateStr,?dateFormat,?true); ????} }
通過單元測試驗證:
class?DateValidatorUsingCommonsValidatorTest?{ ????@Test ????void?isValid()?{ ????????final?DateValidator?dateValidator?=?new?DateValidatorUsingCommonsValidator("yyyy-MM-dd"); ????????Assertions.assertTrue(dateValidator.isValid("2021-02-28")); ????????Assertions.assertFalse(dateValidator.isValid("2021-02-30")); ????} }
看org.apache.commons.validator.DateValidator#isValid
源碼可以發(fā)現(xiàn),內(nèi)部是通過DateFormat
和SimpleDateFormat
實現(xiàn)的。
總結(jié)
在本文中,我們通過四種方式實現(xiàn)了時間字符串校驗邏輯。其中DateFormat
和SimpleDataFormat
是非線程安全的,所以每次方法調(diào)用時,都需要新建實例;通過觀察apache.commons.validator.DateValidator#isValid
的源碼發(fā)現(xiàn),它的內(nèi)部也是通過DateFormat
和SimpleDateFormat
實現(xiàn)的;而LocalDate和DateTimeFormatter則為JDK8中提供的實現(xiàn)方法。
到此這篇關(guān)于Java檢查日期字符串是否合法的方法總結(jié)的文章就介紹到這了,更多相關(guān)Java檢查日期字符串內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中java.sql.SQLException異常的正確解決方法(親測有效!)
SQLException是在Java中處理數(shù)據(jù)庫操作過程中可能發(fā)生的異常,通常是由于底層數(shù)據(jù)庫操作錯誤或違反了數(shù)據(jù)庫規(guī)則而引起的,下面這篇文章主要給大家介紹了關(guān)于Java中java.sql.SQLException異常的正確解決方法,需要的朋友可以參考下2024-01-01Mybatis-plus配置分頁插件返回統(tǒng)一結(jié)果集
本文主要介紹了Mybatis-plus配置分頁插件返回統(tǒng)一結(jié)果集,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06基于Java的Socket多客戶端Client-Server聊天程序的實現(xiàn)
這篇文章主要介紹了基于Java的Socket多客戶端Client-Server聊天程序的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03JAVA對list集合進行排序Collections.sort()
這篇文章主要介紹了JAVA對list集合進行排序Collections.sort(),需要的朋友可以參考下2017-01-01idea項目啟動報錯,日志包沖突slf4j和logback沖突問題
遇到SLF4J沖突時,可以嘗試移除沖突的綁定或調(diào)整項目依賴,具體方法包括刪除多余的Logger綁定庫,如Logback或Log4j,或在項目配置文件中明確指定使用的日志框架,若使用WebLogic服務(wù)器,需在weblogic.xml中進行特定配置,適當(dāng)調(diào)整pom.xml文件中的依賴版本也可能解決問題2024-09-09