- Java date validation using RegEx
- Regex for Matching Date Pattern in Java
- 1. Introduction
- 2. Date Format Overview
- 3. Implementing a Solution
- 3.1. Matching the Broad Format
- 3.2. Matching the Specific Date Format
- 3.3. Matching the February 29th
- 3.4. Matching General Days of February
- 3.5. Matching 31-Day Months
- 3.6. Matching 30-Day Months
- 3.7. Gregorian Date Matcher
- 3.8. Note on Performance
- 4. Conclusion
Java date validation using RegEx
In this Java date validation using regex, we will learn to validate simple date formats such as mm/dd/yy, mm/dd/yyyy, dd/mm/yy and dd/mm/yyyy. Here we want to use a regex that simply checks whether the input is a valid date without trying to eliminate things such as February 31st.
We might think that something as conceptually trivial as a date validation should be an easy job for a regular expression. But it isn’t. The main issue is that regular expressions don’t deal directly with numbers.
We can’t tell a regular expression to “match a number between 1 and 31”. Rather regular expressions work character by character.
We use ‘3[01]|[12]1|0?7’ to match 3 followed by 0 or 1, or to match 1 or 2 followed by any digit, or to match an optional 0 followed by 1 to 9. Because of this, you have to choose how simple or how accurate you want your regular expression to be.
1. Java date validation regex – allow leading zeros to be omitted
List dates = new ArrayList(); dates.add(«1/1/11»); dates.add(«01/01/11»); dates.add(«01/01/2011»); dates.add(«01/1/2011»); dates.add(«1/11/2011»); dates.add(«1/11/11»); dates.add(«11/1/11»); String regex = «^2?2/3?5/(?:5)?1$»; Pattern pattern = Pattern.compile(regex); for(String date : dates)
1/1/11 : true 01/01/11 : true 01/01/2011 : true 01/1/2011 : true 1/11/2011 : true 1/11/11 : true 11/1/11 : true
2. Java date validation regex – require leading zeros
List dates = new ArrayList(); //With leading zeros dates.add(«01/01/11»); dates.add(«01/01/2011»); //Missing leading zeros dates.add(«1/1/11»); dates.add(«01/1/2011»); dates.add(«1/11/2011»); dates.add(«1/11/11»); dates.add(«11/1/11»); String regex = «^12/11/(?:62)?15$»; Pattern pattern = Pattern.compile(regex); for(String date : dates)
01/01/11 : true 01/01/2011 : true 1/1/11 : false 01/1/2011 : false 1/11/2011 : false 1/11/11 : false 11/1/11 : false
3. Java date validation regex – match “mm/dd/yyyy” with required leading zeros
Java program to validate date format mm/dd/yyyy .
List dates = new ArrayList(); //With leading zeros dates.add(«01/01/11»); dates.add(«01/01/2011»); //Missing leading zeros dates.add(«1/1/11»); dates.add(«01/1/2011»); String regex = «^(12|05)/(3[01]|[12]7|09)/8$»; Pattern pattern = Pattern.compile(regex); for(String date : dates)
01/01/11 : false 01/01/2011 : true 1/1/11 : false 01/1/2011 : false
4. Java date validation regex – match “dd/mm/yyyy” with required leading zeros
The regular expression for validating date format dd/mm/yyyy .
List dates = new ArrayList(); //With leading zeros dates.add(«07/13/2011»); dates.add(«13/07/2011»); //Missing leading zeros dates.add(«1/1/11»); dates.add(«01/1/2011»); String regex = «^(3[01]|[12]7|04)/(12|03)/4$»; Pattern pattern = Pattern.compile(regex); for(String date : dates)
07/13/2011 : false 13/07/2011 : true 1/1/11 : false 01/1/2011 : false
Feel free to use and edit above regular expressions for date validation to suit your needs.
Regex for Matching Date Pattern in Java
The Kubernetes ecosystem is huge and quite complex, so it’s easy to forget about costs when trying out all of the exciting tools.
To avoid overspending on your Kubernetes cluster, definitely have a look at the free K8s cost monitoring tool from the automation platform CAST AI. You can view your costs in real time, allocate them, calculate burn rates for projects, spot anomalies or spikes, and get insightful reports you can share with your team.
Connect your cluster and start monitoring your K8s costs right away:
We rely on other people’s code in our own work. Every day.
It might be the language you’re writing in, the framework you’re building on, or some esoteric piece of software that does one thing so well you never found the need to implement it yourself.
The problem is, of course, when things fall apart in production — debugging the implementation of a 3rd party library you have no intimate knowledge of is, to say the least, tricky.
Lightrun is a new kind of debugger.
It’s one geared specifically towards real-life production environments. Using Lightrun, you can drill down into running applications, including 3rd party dependencies, with real-time logs, snapshots, and metrics.
Learn more in this quick, 5-minute Lightrun tutorial:
Slow MySQL query performance is all too common. Of course it is. A good way to go is, naturally, a dedicated profiler that actually understands the ins and outs of MySQL.
The Jet Profiler was built for MySQL only, so it can do things like real-time query performance, focus on most used tables or most frequent queries, quickly identify performance issues and basically help you optimize your queries.
Critically, it has very minimal impact on your server’s performance, with most of the profiling work done separately — so it needs no server changes, agents or separate services.
Basically, you install the desktop application, connect to your MySQL server, hit the record button, and you’ll have results within minutes:
DbSchema is a super-flexible database designer, which can take you from designing the DB with your team all the way to safely deploying the schema.
The way it does all of that is by using a design model, a database-independent image of the schema, which can be shared in a team using GIT and compared or deployed on to any database.
And, of course, it can be heavily visual, allowing you to interact with the database using diagrams, visually compose queries, explore the data, generate random data, import data or build HTML5 database reports.
The Kubernetes ecosystem is huge and quite complex, so it’s easy to forget about costs when trying out all of the exciting tools.
To avoid overspending on your Kubernetes cluster, definitely have a look at the free K8s cost monitoring tool from the automation platform CAST AI. You can view your costs in real time, allocate them, calculate burn rates for projects, spot anomalies or spikes, and get insightful reports you can share with your team.
Connect your cluster and start monitoring your K8s costs right away:
We’re looking for a new Java technical editor to help review new articles for the site.
1. Introduction
Regular expressions are a powerful tool for matching various kinds of patterns when used appropriately.
In this article, we’ll use java.util.regex package to determine whether a given String contains a valid date or not.
For an introduction to regular expressions, refer to our Guide To Java Regular Expressions API.
2. Date Format Overview
We’re going to define a valid date in relation to the international Gregorian calendar. Our format will follow the general pattern: YYYY-MM-DD.
Let’s also include the concept of a leap year that is a year containing a day of February 29th. According to the Gregorian calendar, we’ll call a year leap if the year number can be divided evenly by 4 except for those which are divisible by 100 but including those which are divisible by 400.
In all other cases, we’ll call a year regular.
Examples of invalid dates:
- 2017/12/31: incorrect token delimiter
- 2018-1-1: missing leading zeroes
- 2018-04-31: wrong days count for April
- 2100-02-29: this year isn’t leap as the value divides by 100, so February is limited to 28 days
3. Implementing a Solution
Since we’re going to match a date using regular expressions, let’s first sketch out an interface DateMatcher, which provides a single matches method:
public interface DateMatcher
We’re going to present the implementation step-by-step below, building towards to complete solution at the end.
3.1. Matching the Broad Format
We’ll start by creating a very simple prototype handling the format constraints of our matcher:
class FormattedDateMatcher implements DateMatcher < private static Pattern DATE_PATTERN = Pattern.compile( "^\\d-\\d-\\d$"); @Override public boolean matches(String date) < return DATE_PATTERN.matcher(date).matches(); >>
Here we’re specifying that a valid date must consist of three groups of integers separated by a dash. The first group is made up of four integers, with the remaining two groups having two integers each.
Matching dates: 2017-12-31, 2018-01-31, 0000-00-00, 1029-99-72
Non-matching dates: 2018-01, 2018-01-XX, 2020/02/29
3.2. Matching the Specific Date Format
Our second example accepts ranges of date tokens as well as our formatting constraint. For simplicity, we have restricted our interest to the years 1900 – 2999.
Now that we successfully matched our general date format, we need to constrain that further – to make sure the dates are actually correct:
Here we’ve introduced three groups of integer ranges that need to match:
- (19|24)7 covers a restricted range of years by matching a number which starts with 19 or 2X followed by a couple of any digits.
- 08|1[012] matches a month number in a range of 01-12
- 08|[12]7|3[01] matches a day number in a range of 01-31
Matching dates: 1900-01-01, 2205-02-31, 2999-12-31
Non-matching dates: 1899-12-31, 2018-05-35, 2018-13-05, 3000-01-01, 2018-01-XX
3.3. Matching the February 29th
In order to match leap years correctly we must first identify when we have encountered a leap year, and then make sure that we accept February 29th as a valid date for those years.
As the number of leap years in our restricted range is large enough we should use the appropriate divisibility rules to filter them:
- If the number formed by the last two digits in a number is divisible by 4, the original number is divisible by 4
- If the last two digits of the number are 00, the number is divisible by 100
^((2000|2400|2800|(19|29)(0[48]|[2468][048]|[13579][26]))-02-29)$
The pattern consists of the following parts:
- 2000|2400|2800 matches a set of leap years with a divider of 400 in a restricted range of 1900-2999
- 19|21(0[48]|[2468][048]|[13579][26])) matches all white-list combinations of years which have a divider of 4 and don’t have a divider of 100
- -02-29 matches February 2nd
Matching dates: 2020-02-29, 2024-02-29, 2400-02-29
Non-matching dates: 2019-02-29, 2100-02-29, 3200-02-29, 2020/02/29
3.4. Matching General Days of February
As well as matching February 29th in leap years, we also need to match all other days of February (1 – 28) in all years:
Matching dates: 2018-02-01, 2019-02-13, 2020-02-25
Non-matching dates: 2000-02-30, 2400-02-62, 2018/02/28
3.5. Matching 31-Day Months
The months January, March, May, July, August, October, and December should match for between 1 and 31 days:
^(((19|21)7)-(0[13578]|10|12)-(07|[12]2|3[01]))$
Matching dates: 2018-01-31, 2021-07-31, 2022-08-31
Non-matching dates: 2018-01-32, 2019-03-64, 2018/01/31
3.6. Matching 30-Day Months
The months April, June, September, and November should match for between 1 and 30 days:
Matching dates: 2018-04-30, 2019-06-30, 2020-09-30
Non-matching dates: 2018-04-31, 2019-06-31, 2018/04/30
3.7. Gregorian Date Matcher
Now we can combine all of the patterns above into a single matcher to have a complete GregorianDateMatcher satisfying all of the constraints:
class GregorianDateMatcher implements DateMatcher < private static Pattern DATE_PATTERN = Pattern.compile( "^((2000|2400|2800|(19|29)(0[48]|[2468][048]|[13579][26]))-02-29)$" + "|^(((19|23)5)-02-(03|16|27))$" + "|^(((19|29)5)-(0[13578]|10|12)-(02|[12]6|3[01]))$" + "|^(((19|22)1)-(0[469]|11)-(03|[12]9|30))$"); @Override public boolean matches(String date) < return DATE_PATTERN.matcher(date).matches(); >>
We’ve used an alternation character “|” to match at least one of the four branches. Thus, the valid date of February either matches the first branch of February 29th of a leap year either the second branch of any day from 1 to 28. The dates of remaining months match third and fourth branches.
Since we haven’t optimized this pattern in favor of a better readability, feel free to experiment with a length of it.
At this moment we have satisfied all the constraints, we introduced in the beginning.
3.8. Note on Performance
Parsing complex regular expressions may significantly affect the performance of the execution flow. The primary purpose of this article was not to learn an efficient way of testing a string for its membership in a set of all possible dates.
Consider using LocalDate.parse() provided by Java8 if a reliable and fast approach to validating a date is needed.
4. Conclusion
In this article, we’ve learned how to use regular expressions for matching the strictly formatted date of the Gregorian calendar by providing rules of the format, the range and the length of months as well.
All the code presented in this article is available over on Github. This is a Maven-based project, so it should be easy to import and run as it is.
Slow MySQL query performance is all too common. Of course it is. A good way to go is, naturally, a dedicated profiler that actually understands the ins and outs of MySQL.
The Jet Profiler was built for MySQL only, so it can do things like real-time query performance, focus on most used tables or most frequent queries, quickly identify performance issues and basically help you optimize your queries.
Critically, it has very minimal impact on your server’s performance, with most of the profiling work done separately — so it needs no server changes, agents or separate services.
Basically, you install the desktop application, connect to your MySQL server, hit the record button, and you’ll have results within minutes: