I need to validate date in java the input date can be anything like
01-01-2019,2019-01-01,2019/01/01,2019/01/01,2017-02-14 19:30.
I have the following code that can validate simple date without timestamp. I need to validate date with timestamp as well.In following code i have written a parseDate method which gives me format of date which we pass.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String date1 = parseDate("12-12-2019 10:10:10");
boolean str1 = isValid(date1,"12-12-2019 10:10:10");
System.out.println("str = " + str1);
}
private static final String[] formats = {
"yyyy-MM-dd'T'HH:mm:ss'Z'","yyyy-MM-dd'T'HH:mm:ssZ",
"yyyy-MM-dd'T'HH:mm:ss","yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
"yyyy-MM-dd'T'HH:mm:ss.SSSZ","yyyy-MM-dd HH:mm:ss",
"MM/dd/yyyy HH:mm:ss","MM/dd/yyyy'T'HH:mm:ss.SSS'Z'",
"MM/dd/yyyy'T'HH:mm:ss.SSSZ", "MM/dd/yyyy'T'HH:mm:ss.SSS",
"MM/dd/yyyy'T'HH:mm:ssZ","MM/dd/yyyy'T'HH:mm:ss",
"yyyy:MM:dd HH:mm:ss","yyyy-MM-dd HH:mm:ss.SSSSSS",
"yyyy/MM/dd HH:mm:ss","MM/dd/yyyy","dd/MM/yyyy",
"dd-MM-yyyy","yyyy/MM/dd"
};
public static String parseDate(String dateString) {
int count = 0;
if (dateString != null) {
for (String dateFormat : formats) {
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
sdf.setLenient(false);
try {
count ++;
sdf.parse(dateString);
System.out.println("sdf.parse(dateString);" + sdf.parse(dateString));
System.out.println("dateFormat " + dateFormat);
System.out.println("count" + count);
return dateFormat;
} catch (ParseException e) {
}
}
}
return "yyyy-MM-dd";
}
public static boolean isValid(String format,String inDate) {
System.out.println("format " + format);
System.out.println("inDate " + inDate);
if (inDate == null || !inDate.matches("^([0-2][0-9]|(3)[0-1])(\\-)(((0)[0-9])|((1)[0-2]))(\\-)\\d{4}$")
&& !inDate.matches("^([0-2][0-9]|(3)[0-1])(\\/)(((0)[0-9])|((1)[0-2]))(\\/)\\d{4}$")
&& !inDate.matches("([12]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]))")
&& !inDate.matches("([12]\\d{3}/(0[1-9]|1[0-2])/(0[1-9]|[12]\\d|3[01]))"))
return false;
SimpleDateFormat df = new SimpleDateFormat(format);
try {
df.parse(inDate);
return true;
} catch (ParseException ex) {
return false;
}
}
Not possible to accommodate all formats
"MM/dd/yyyy","dd/MM/yyyy"
It is impossible to accurately parse such values.
Is 01/02/2020
the first of February or the second of January? No way to know.
Avoid legacy date-time classes
You are using the wrong classes. Never use Date
, SimpleDateFormat
, Calendar
, and such. Use only java.time classes.
- The
Date
class represents a moment, not a date nor a date-with-time. A moment is a date, a time-of-day, and an offset-from-UTC or time zone. - And that terrible class was supplanted years ago by
java.time.Instant
as of the adoption of JSR 310.
ISO 8601
By the way, the ISO 8601 standard defines practical formats for exchanging date-time values as text. The formats are easy to parse by machine, and easy to read by humans across cultures.
I suggest you educate the publisher of your data about these standard formats.
Tip: The modern java.time classes use these formats by default when parsing/generating strings. So no need to specify a formatting pattern.
LocalDate
The LocalDate
class represents a date-only value without time-of-day and without time zone or offset-from-UTC.
DateTimeFormatter
Define a DateTimeFormatter
for each of your expected formats.
Notice how I changed your example data to use 23
for day-of-month, to distinguish month versus day. If your actual inputs can be in either order, then your job is impossible. You should push this problem back to the people publishing such haphazard poorly-formatted data.
List< DateTimeFormatter > formatters =
List.of(
DateTimeFormatter.ofPattern( "MM-dd-uuuu" ) , // 01-23-2019
DateTimeFormatter.ISO_LOCAL_DATE , // 2019-01-23
DateTimeFormatter.ofPattern( "uuuu/MM/dd" ) // 2019/01/23
)
;
Loop that list to try each one, trapping for exception when a misfit.
LocalDate localDate = null ;
for( DateTimeFormatter f : formatters ) {
try{
localDate = LocalDate.parse( input , f ) ;
} catch ( DateTimeParseException e ) {
// Ignoring exception, as it is expected.
}
}
if( Objects.isNull( localDate ) ) { … deal with unexpected input }
LocalDateTime
And check length of input to detect the date-with-time inputs versus date-only inputs.
if( input.length() > 10 ) {
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm" ) ; // 2017-02-14 19:30
LocalDateTime ldt = LocalDateTime.parse( input , f ) ; // Add trap for `DateTimeParseException`.
}
Example app
Here is an entire working example app.
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
import java.time.* ;
import java.time.format.* ;
import java.time.temporal.* ;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
List< DateTimeFormatter > formatters =
List.of(
DateTimeFormatter.ofPattern( "MM-dd-uuuu" ) , // 01-23-2019
DateTimeFormatter.ISO_LOCAL_DATE , // 2019-01-23
DateTimeFormatter.ofPattern( "uuuu/MM/dd" ) // 2019/01/23
)
;
List< String > inputs =
List.of(
"01-23-2019" ,
"2019-01-23" ,
"2019/01/23" ,
"banana"
)
;
for( String input : inputs ) {
LocalDate localDate = null ;
for( DateTimeFormatter formatter : formatters )
{
try{
localDate = LocalDate.parse( input , formatter ) ;
} catch ( DateTimeParseException e ) {
// Ignoring exception, as it is expected.
}
}
if( Objects.isNull( localDate ) )
{ // Deal with unexpected input
System.out.println( "ERROR: Unexpected input: " + input ) ;
} else {
System.out.println( "Input: " + input + " ➙ " + localDate.toString() ) ;
}
}
}
}
See it run live at IdeOne.com.
Input: 01-23-2019 ➙ 2019-01-23
Input: 2019-01-23 ➙ 2019-01-23
Input: 2019/01/23 ➙ 2019-01-23
ERROR: Unexpected input: banana