How to convert String to Date without knowing the format?

JavaDateFormat

Java Problem Overview


I have a problem. I am trying to convert some strings to date, and I don't know the format the date is arriving.

It might come as yyyy.mm.dd hh:mm:ss or MM.dd.yy hh:mm:ss and so on.

How can I convert these strings to Date? I tried this:

DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
Date d = (Date)formatter.parse(someDate);

But when I printed out someDate it printed out like this: 2010-08-05 12:42:48.638 CEST which means yyyy.mm.dd hh:mm:ss, however when I ran the above code, the date object now became Sat Jan 31 00:42:48 CET 11 which is strange to say the least.

Any ideas how I can correctly format strings to date?

Java Solutions


Solution 1 - Java

You cant!

If you have the date 2010-08-05 then it can be either 5th August 2010, or 8th May 2010 - you need to know the date format (or at least prioritise one format over the over) to tell them apart.

Solution 2 - Java

I agree with Kragen that in the general case there is no correct solution. However, if the following conditions hold, you may use the solution below:

  1. You have a set of all possible formats

  2. There is no ambiguity between the formats; no date expression can be successfully parsed by two of them.

Consider the following solution which iterates over a list of possible formats. This solution makes use of ThreadLocal, in order to make date parsing efficient in a multi-threaded environment (remember that SimpleDateFormat isn't thread safe):

public class FlexibleDateParser {
	private List<ThreadLocal<SimpleDateFormat>> threadLocals = new  ArrayList<ThreadLocal<SimpleDateFormat>>();

	public FlexibleDateParser(List<String> formats, final TimeZone tz){
		threadLocals.clear();
		for (final String format : formats) {
			ThreadLocal<SimpleDateFormat> dateFormatTL = new ThreadLocal<SimpleDateFormat>() {
				protected SimpleDateFormat initialValue() {
					SimpleDateFormat sdf = new SimpleDateFormat(format);
					sdf.setTimeZone(tz); 
					sdf.setLenient(false);
					return sdf;
				}
			};
			threadLocals.add(dateFormatTL);
		}		
	}
	
	public Date parseDate(String dateStr) throws ParseException {
		for (ThreadLocal<SimpleDateFormat> tl : threadLocals) {
			SimpleDateFormat sdf = tl.get();
			try {
				return sdf.parse(dateStr);
			} catch (ParseException e) {
				// Ignore and try next date parser
			}
		}
		// All parsers failed
		return null;
	}		
}

Solution 3 - Java

As noted before, you need to at least have an ordered list of pattern candidates. Once you have that, Apache DateUtils has a parseDate(String dateString, String[] patterns) method that lets you easily try out a list of patterns on your date string, and parse it by the first one that matches:

public static Date parseDate(String str,
                         String[] parsePatterns)
                  throws ParseException

>Parses a string representing a date by trying a variety of different parsers.

>The parse will try each parse pattern in turn. A parse is only deemed successful if it parses the whole of the input string. If no parse patterns match, a ParseException is thrown.

>The parser will be lenient toward the parsed date.

Solution 4 - Java

Here is a quick and dirty solution based on american date formats.

public Date parseDate(String strDate) throws Exception
{
	if (strDate != null && !strDate.isEmpty())
	{
		SimpleDateFormat[] formats =
				new SimpleDateFormat[] {new SimpleDateFormat("MM-dd-yyyy"), new SimpleDateFormat("yyyyMMdd"),
						new SimpleDateFormat("MM/dd/yyyy")};

		Date parsedDate = null;

		for (int i = 0; i < formats.length; i++)
		{
			try
			{
				parsedDate = formats[i].parse(strDate);
				return parsedDate;
			}
			catch (ParseException e)
			{
				continue;
			}
		}
	}
	throw new Exception("Unknown date format: '" + strDate + "'");
}

Solution 5 - Java

Your problem is related to Internationalization. As Kragen answered, you can't just parse date in unknown format. Although you can scan all possible locales and parse something, but you wouldn't know if it was parsed correctly.

Just a little i18n background:

Q: Can you tell me what day month and year this date is referring to:

09/11/10?

A: Without knowing the locale, you can't. It could be anything. September, 11th in USA. November, 9th in Great Britain. And so on.

Solution 6 - Java

This answer is a copy of my answer to another question that is marked as duplicate of this one

I once had a task to write a code that would parse a String to date where date format was not known in advance. I.e. I had to parse any valid date format. I wrote a project and after that I wrote an article that described the idea behind my implementation. Here is the link to the article: Java 8 java.time package: parsing any string to date. General Idea is to write all the patterns that you wish to support into external properties file and read them from there and try to parse your String by those formats one by one until you succeed or run out of formats. Note that the order also would be important as some Strings may be valid for several formats (US/European differences). Advantage is that you can keep adding/removing formats to the file without changing your code. So such project could also be customized for different customers

Solution 7 - Java

If its a protocol; define the format - perhaps ISO that will irritate everyone except us in sweden...

If it input from users; Let them set their locale. If you can do it, show the parsed date in full format so the user can verify it, like November 10, 2009.

Solution 8 - Java

My only guess, is that you should gather some statistics first to figure out the format.

If you're lucky, you will have date like "2010/08/13" which can be parsed unambiguously

Solution 9 - Java

Here is the simple solution, which is worked for me. This is the simple method to parse the date, pass the String as argument & parse it in any format those you want.

String dateToConvert(String date) {
        String strDate = "";
        try {
            //create SimpleDateFormat object with source string date format
            DateFormat sdfSource = new SimpleDateFormat("yyyy-MM-dd");

            //parse the string into Date object
            Date d = sdfSource.parse(date);
            LocalLog.e(LOG_TAG, d.toString());
            //create SimpleDateFormat object with desired date format
            SimpleDateFormat sdfDestination = new SimpleDateFormat(AppConstants.UNIVERSAL_DATE_FORMAT);

            //parse the date into another format
            strDate = sdfDestination.format(d);

            LocalLog.e(LOG_TAG, strDate);

        } catch (ParseException pe) {
            System.out.println("Parse Exception : " + pe);
        }
        return strDate;
    }

Solution 10 - Java

I created a utility that tries to parse some common date formats. It tries to check which digit is greater than 12 or else if both are less than 12 it prefers user-defined boolean preferMonthFirst based on which it will choose between MM/dd/yyyy or dd/MM/yyyy

It also accepts prefer24HourTime boolean for parsing time.

I did not use the list and iterate over it and try to parse it and tried to catch exception because Exceptions are costlier. So based on separator and length I tried to find the date format.

You can find usages in the test cases.

https://github.com/rajat-g/DateParser

Solution 11 - Java

public  String compareDate( PaymentTxnRequest request ) throws ParseException { 
	    Date debitDate=	request.getPaymentTxn().getCrValDt();
		Date now = new Date();
		String response="";
	    SimpleDateFormat sdfDate = new SimpleDateFormat("dd/MM/yyyy");
	    String strCurrDate = sdfDate.format(now);
	    String strDebitDate = sdfDate.format(debitDate);
	    System.out.println("Current Date: " + strCurrDate);
	    Date currentDate =  new SimpleDateFormat("dd/MM/yyyy").parse(strCurrDate);
	    Date txnDate =  new SimpleDateFormat("dd/MM/yyyy").parse(strDebitDate);
	    System.out.println("C -> "+currentDate);
	    System.out.println("C -> "+txnDate); 
	  	 if (txnDate!=null){
		 if (currentDate.equals(txnDate))
		 {
			 System.out.println("Valid Txn");
			 response="valid";
		 }
		 if (currentDate.after(txnDate))
    	 {
	     	System.out.println("--> Not  Valid TXN Past");	 
		    response="notValid";
    	 }
		if (currentDateenter code here.before(txnDate)){
			System.out.println("Future Valid TXn");
			 response="future";
		}
	 }
		return response;
	}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShervin AsgariView Question on Stackoverflow
Solution 1 - JavaJustinView Answer on Stackoverflow
Solution 2 - JavaEyal SchneiderView Answer on Stackoverflow
Solution 3 - JavaoksaytView Answer on Stackoverflow
Solution 4 - JavabjoernView Answer on Stackoverflow
Solution 5 - JavaPaweł DydaView Answer on Stackoverflow
Solution 6 - JavaMichael GantmanView Answer on Stackoverflow
Solution 7 - JavaKarlPView Answer on Stackoverflow
Solution 8 - JavaAlexander MalakhovView Answer on Stackoverflow
Solution 9 - JavaMaheshwar LigadeView Answer on Stackoverflow
Solution 10 - JavaRajat GuptaView Answer on Stackoverflow
Solution 11 - JavaVignesh AnandView Answer on Stackoverflow