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,一经查实,立即删除!

相关文章

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

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

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

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

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;运动时仅考虑初始速度、重力加速度…

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

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

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

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

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…

工作中常用的 6 种设计模式!

前言 哈喽&#xff0c;大家好。平时我们写代码呢&#xff0c;多数情况都是流水线式写代码&#xff0c;基本就可以实现业务逻辑了。如何在写代码中找到乐趣呢&#xff0c;我觉得&#xff0c;最好的方式就是&#xff1a;使用设计模式优化自己的业务代码。今天跟大家聊聊日常工作中…

【Matlab/C/Python/VB/...】代码复制到word时如何变成彩色的

文章目录下载Notepad复制代码在Notepad粘贴在word中粘贴下载Notepad Notepad是一款免费的Windows软件&#xff0c;一般Windows10和Windows7系统都已经自带&#xff0c;也可以在应用商店直接搜索下载 「win10系统兼容的是7.8版本」 复制代码 在语言编辑乱码复制代码&#xff…

hadoop 2.5.0安装和配置

安装hadoop要先做以下准备&#xff1a; 1.jdk&#xff0c;安装教程在 http://www.cnblogs.com/stardjyeah/p/4640917.html 2.ssh无密码验证&#xff0c;配置教程在 http://www.cnblogs.com/stardjyeah/p/4641524.html 3.linux静态ip配置&#xff0c;教程在 http://www.cnblo…

基于双线性插值的图像旋转原理及MATLAB实现(非自带函数)

目录1.图像旋转的原理1.1.旋转矩阵1.2.双线性插值1.3.像素点匹配2.实现效果与说明1.图像旋转的原理 1.1.旋转矩阵 旋转一幅图像&#xff08;假设这幅图像大小是矩形的&#xff09;&#xff0c;当然应该从像素点&#xff08;pixels&#xff09;开始&#xff0c;在直角坐标系中…

漫画:给女朋友介绍什么是 “元宇宙” ?

什么是更高的自由度呢&#xff1f;或许有人觉得&#xff0c;我们在网络游戏当中&#xff0c;不是也很自由吗&#xff1f;想怎么玩就怎么玩。但是&#xff0c;无论一款网络游戏的元素有多么丰富&#xff0c;游戏当中的角色、任务、职业、道具、场景&#xff0c;都是游戏设计师预…

MyBatis 中为什么不建议使用 where 1=1?

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;最近接手了一个老项目&#xff0c;“愉悦的心情”自然无以言表&#xff0c;做开发的朋友都懂&#xff0c;这里就不多说了&am…

【openMV与机器视觉】四旋翼飞行控制背景下的PID控制与摄像头算法简介

文章目录声明1.四旋翼飞行控制简介2.飞行控制算法2.1.接收机PWM生成2.2.PID算法位置PID速度PID3.摄像头算法3.1.图像处理3.2.霍夫曼变换3.3.巡线算法3.3.寻找目标点降落算法声明 \qquad本文的算法在openMV IDE例程的基础上进行原创&#xff0c;在比赛结束后予以发表&#xff1b…

聊聊sql优化的15个小技巧

前言sql优化是一个大家都比较关注的热门话题&#xff0c;无论你在面试&#xff0c;还是工作中&#xff0c;都很有可能会遇到。如果某天你负责的某个线上接口&#xff0c;出现了性能问题&#xff0c;需要做优化。那么你首先想到的很有可能是优化sql语句&#xff0c;因为它的改造…