4 种方法!检查字符串是否为合法的日期格式

0498de290532274014942133cf0ea2ed.png

哈喽大家好,今天咱们来讲一下,Java 中如何检查一个字符串是否是合法的日期格式?

为什么要检查时间格式?

后端接口在接收数据的时候,都需要进行检查。检查全部通过后,才能够执行业务逻辑。对于时间格式,我们一般需要检查这么几方面:

  1. 字符串格式是否正确,比如格式是不是yyyy-MM-dd

  2. 时间在合法范围内,比如我们需要限定在一个月内的时间

  3. 字符串可以解析为正常的时间,比如 2 月 30 号就不是正常时间

对于时间格式的判断,我们可以通过正则表达式来检查。不过考虑到正则表达式的性能、输入数据的复杂性,一般能用别的方式,就不选正则表达式。我们还是选择一种更加通用、更加高效的检查方式。

首先,定义时间校验器的接口:

public interface DateValidator {boolean isValid(String dateStr);
}

接口方法接收一个字符串,返回布尔类型,表示字符串是否是合法的时间格式。

实现方法

接下来就是通过不同方式实现DateValidator

1.使用 DateFormat 检查

Java 提供了格式化和解析时间的工具:DateFormat抽象类和SimpleDataFormat实现类。我们借此实现时间校验器:

public class DateValidatorUsingDateFormat implements DateValidator {private final String dateFormat;public DateValidatorUsingDateFormat(String dateFormat) {this.dateFormat = dateFormat;}@Overridepublic 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;}
}

这里需要注意一下,DateFormatSimpleDataFormat是非线程安全的,所以每次方法调用时,都需要新建实例。

我们通过单元测试验证下:

class DateValidatorUsingDateFormatTest {@Testvoid 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(想要了解更多内容,请移步参看 Java8 中的时间类及常用 API)。其中包括LocalDate类,是一个不可变且线程安全的时间类。

LocalDate提供了两个静态方法,用来解析时间。这两个方法内部都是使用java.time.format.DateTimeFormatter来处理数据:

// 使用 DateTimeFormatter.ISO_LOCAL_DATE 处理数据
public static LocalDate parse(CharSequence text) {return parse(text, DateTimeFormatter.ISO_LOCAL_DATE);
}// 使用提供的 DateTimeFormatter 处理数据
public static LocalDate parse(CharSequence text, DateTimeFormatter formatter) {Objects.requireNonNull(formatter, "formatter");return formatter.parse(text, LocalDate::from);
}

通过LocalDateparse方法实现我们的校验器:

public class DateValidatorUsingLocalDate implements DateValidator {private final DateTimeFormatter dateFormatter;public DateValidatorUsingLocalDate(DateTimeFormatter dateFormatter) {this.dateFormatter = dateFormatter;}@Overridepublic boolean isValid(String dateStr) {try {LocalDate.parse(dateStr, this.dateFormatter);} catch (DateTimeParseException e) {return false;}return true;}
}

java.time.format.DateTimeFormatter类是不可变的,也就是天然的线程安全,我们可以在不同线程使用同一个校验器实例。

我们通过单元测试验证下:

class DateValidatorUsingLocalDateTest {@Testvoid 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实现的,那我们也可以直接使用DateTimeFormatter

3.使用 DateTimeFormatter 检查

DateTimeFormatter解析文本总共分两步。第一步,根据配置将文本解析为日期和时间字段;第二步,用解析后的字段创建日期和时间对象。

实现验证器:

public class DateValidatorUsingDateTimeFormatter implements DateValidator {private final DateTimeFormatter dateFormatter;public DateValidatorUsingDateTimeFormatter(DateTimeFormatter dateFormatter) {this.dateFormatter = dateFormatter;}@Overridepublic 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);@Testvoid 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"));}
}

可以看到,我们指定了转换模式是ResolverStyle.STRICT,这个类型是说明解析模式。共有三种:

  • STRICT:严格模式,日期、时间必须完全正确。

  • SMART:智能模式,针对日可以自动调整。月的范围在 1 到 12,日的范围在 1 到 31。比如输入是 2 月 30 号,当年 2 月只有 28 天,返回的日期就是 2 月 28 日。

  • LENIENT:宽松模式,主要针对月和日,会自动后延。结果类似于LocalData#plusDays或者LocalDate#plusMonths

我们通过例子看下区别:

class DateValidatorUsingDateTimeFormatterTest {private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd", Locale.CHINA);@Testvoid 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可以最大程度将字符串转化为时间对象,在合理范围内可以随便玩;ResolverStyle.SMART名为智能,但智力有限,两不沾边,优势不够明显。JDK 提供的DateTimeFormatter实现,都是ResolverStyle.STRICT模式。

说了 JDK 自带的实现,接下来说说第三方组件的实现方式。

4.使用 Apache 出品的 commons-validator 检查

Apache Commons 项目提供了一个校验器框架,包含多种校验规则,包括日期、时间、数字、货币、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>

实现验证器:

public class DateValidatorUsingCommonsValidator implements DateValidator {private final String dateFormat;public DateValidatorUsingCommonsValidator(String dateFormat) {this.dateFormat = dateFormat;}@Overridepublic boolean isValid(String dateStr) {return GenericValidator.isDate(dateStr, dateFormat, true);}
}

通过单元测试验证:

class DateValidatorUsingCommonsValidatorTest {@Testvoid 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源码可以发现,内部是通过DateFormatSimpleDateFormat实现的。

总结

在本文中,我们通过四种方式实现了时间字符串校验逻辑。其中DateFormatSimpleDataFormat是非线程安全的,所以每次方法调用时,都需要新建实例;通过观察apache.commons.validator.DateValidator#isValid的源码发现,它的内部也是通过DateFormatSimpleDateFormat实现的;而LocalDate和DateTimeFormatter则为JDK8中提供的实现方法。

推荐阅读

SpringBoot时间格式化的5种方法!

3种时间格式化的方法,SpringBoot篇!

SpringBoot官方热部署和远程调试神器,真带劲!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544513.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux下tomcat无法显示图片验证码

在catalina.sh中的-Djava.io.tmpdir"$CATALINA_TMPDIR" \后一行增加 -Djava.awt.headlesstrue \ 共8处转载于:https://blog.51cto.com/zhangfeikr/1673312

Java Throwable toString()方法与示例

Throwable类toString()方法 (Throwable Class toString() method) toString() Method is available in java.lang package. toString()方法在java.lang包中可用。 toString() Method is used to return a short description of the exception. toString()方法用于返回对该异常的…

【Matlab】根据图生成带权邻接矩阵,并求出最短路径

目录图的简介无向图&#xff08;Graph&#xff09;生成带权邻接矩阵求两点最短路径有向图&#xff08;Digraph&#xff09;生成带权邻接矩阵求最短路径图的简介 图是拓扑学中的一个重要概念&#xff0c;分为无向图和有向图两种。图有两个重要属性&#xff0c;即点&#xff08;…

阿里二面:为什么要分库分表?

在高并发系统当中&#xff0c;分库分表是必不可少的技术手段之一&#xff0c;同时也是BAT等大厂面试时&#xff0c;经常考的热门考题。你知道我们为什么要做分库分表吗&#xff1f;这个问题要从两条线说起&#xff1a;垂直方向 和 水平方向。1 垂直方向垂直方向主要针对的是业务…

java scanner_Java Scanner nextDouble()方法与示例

java scanner扫描仪类的nextDouble()方法 (Scanner Class nextDouble() method) nextDouble() method is available in java.util package. nextDouble()方法在java.util包中可用。 nextDouble() method is used to scans the next token of the input scanned into a double v…

Java 中 List 分片的 5 种方法!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;前些天在实现 MyBatis 批量插入时遇到了一个问题&#xff0c;当批量插入的数据量比较大时&#xff0c;会导致程序执行报错&a…

Matlab仿真炮弹飞行轨迹——探究射弹参数对飞行轨迹的影响

目录1.分析炮弹受力2.设定参数并仿真3.通过仿真寻找最佳射弹速度3.1.射弹角度的影响3.2.射弹速率的影响3.3.炮弹属性和空气的影响3.3.1.空气阻力系数的影响3.3.2.炮弹质量的影响1.分析炮弹受力 假设炮弹在飞行过程中可以看成质点&#xff0c;运动时仅考虑初始速度、重力加速度…

EL与JSTL注意事项汇总

EL使用表达式&#xff08;5一个 问题&#xff09; JSTL使用标签&#xff08;5问题&#xff09; 什么是EL。它可以用做&#xff1f; EL全名Expression Language在JSP使用页面 格公式${表达式} 样例${requestScope.customer.id} 功能&#xff1a; 1.才四个域对象中取出属性数据显…

nextboolean()_Java Random nextBoolean()方法与示例

nextboolean()随机类nextBoolean()方法 (Random Class nextBoolean() method) nextBoolean() method is available in java.util package. nextBoolean()方法在java.util包中可用。 nextBoolean() method is used to return the next pseudo-random Boolean value from this Ra…

50行代码,搞定敏感数据读写!

每天早上七点三十&#xff0c;准时推送干货一、介绍在实际的软件系统开发过程中&#xff0c;由于业务的需求&#xff0c;在代码层面实现数据的脱敏还是远远不够的&#xff0c;往往还需要在数据库层面针对某些关键性的敏感信息&#xff0c;例如&#xff1a;身份证号、银行卡号、…

【Python】导入资源管理器的文件列表(计算文件和文件夹大小)

文章目录1.按照扩展名进行分类2.导出文件的大小3.计算文件夹大小4.分类到字典5.完整代码及效果1.按照扩展名进行分类 使用Python查询一个路径下的所有文件可以借助glob模块以及os模块。 在导入文件列表之前&#xff0c;我们需要指定我们的操作目录&#xff0c;操作目录一经指定…

SublimeText2使用笔记

将Sublime Text2 加入右键菜单&#xff08;转&#xff09; 1. 运行中输入 regedit 打开注册表 2. 在HKEY_CLASSES_ROOT/*/shell/ 下新建’项’ ,名称自己觉得.我用的是Sublime Text 3. 在 Sublime Text 下 新建’项’ 名字:command (这个貌似不可以修改) 4. 点击 command ,在右…

Java Package getPackage()方法与示例

包类的getPackage()方法 (Package Class getPackage() method) getPackage() method is available in java.lang package. getPackage()方法在java.lang包中可用。 getPackage() method is used to search a package by given package name in the callers ClassLoader instanc…

HashMap 中的一个“坑”!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;最近公司新来了一个小伙伴&#xff0c;问了磊哥一个比较“奇怪”的问题&#xff0c;这个问题本身的难度并不大&#xff0c;但…

【Python】交互式界面创建函数

文章目录简介规则思路示例代码与运行效果简介 运行Python时&#xff0c;在程序运行过程中手动输入一个函数表达式&#xff0c;并将其作为一个函数进行后续的调用工作&#xff0c;类似于Matlab里面的匿名函数。这个功能使用传统语言会相当麻烦&#xff0c;当然&#xff0c;我也…

原生 js前端路由系统实现3之代码 构建工具 和 querystring功能

为什么80%的码农都做不了架构师&#xff1f;>>> 构建 目前前端构建工具流行的是 grunk.js 功能是大而全&#xff0c;但往往大而全的东西为了多样性 需要做额外的配置 我还是想要有一个专门为自己特性项目而生构建工具 我不想加载第三方的node模块&#xff0c;也不…

单例模式,真不简单

前言单例模式无论在我们面试&#xff0c;还是日常工作中&#xff0c;都会面对的问题。但很多单例模式的细节&#xff0c;值得我们深入探索一下。这篇文章透过单例模式&#xff0c;串联了多方面基础知识&#xff0c;非常值得一读。1 什么是单例模式&#xff1f;单例模式是一种非…

【python】最优化方法之一维搜索(黄金分割法+斐波那契法)

文章目录1.概念2.遍历搜索3.优化算法3.1.一维搜索原则3.2.黄金分割法Code Block3.3.斐波拉契法Code Block1.概念 \qquad一维搜索是最优化方法最简单的一种&#xff0c;即求一个在(a,b)内&#xff0c;连续下单峰函数f(x)f(x)f(x)的极小值。所谓下单峰函数就是只有一个极小值的函…

MySQL系列之E-1------MySQL主从复制原理

主从复制是异步复制,可以通过google的一个插件实现半同步E.1 主从复制原理1、建立主从复制的用户名和密码2、将master上主库需要进行复制的库“锁库”3、通过mysqldump备份master上主库&#xff0c;“解锁“&#xff0c;在slave端进行恢复4、更改配置文件5、在丛库上执行change…

Java Long类的valueOf()方法及示例

Syntax: 句法&#xff1a; public static Long valueOf (long value);public static Long valueOf (String value);public static Long valueOf (String value, int radixs);长类valueOf()方法 (Long class valueOf() method) valueOf() method is available in java.lang pac…