96

I know this question is asked quite a bit, and obviously you can't parse any arbitrary date. However, I find that the python-dateutil library is able to parse every date I throw at it, all while requiring absolutely zero effort in figuring out a date format string. Joda time is always sold as being a great Java date parser, but it still requires you to decide what format your date is in before you pick a Format (or create your own). You can't just call DateFormatter.parse(mydate) and magically get a Date object back.

For example, the date "Wed Mar 04 05:09:06 GMT-06:00 2009" is properly parsed with python-dateutil:

import dateutil.parser
print dateutil.parser.parse('Wed Mar 04 05:09:06 GMT-06:00 2009')

but the following Joda time call doesn't work:

    String date = "Wed Mar 04 05:09:06 GMT-06:00 2009";
    DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
    DateTime dt = fmt.parseDateTime(date);
    System.out.println(date);

And creating your own DateTimeFormatter defeats the purpose, since that seems to be the same as using SimpleDateFormatter with the correct format string.

Is there a comparable way to parse a date in Java, like python-dateutil? I don't care about errors, I just want it to mostly perfect.

0

7 Answers 7

124

Your best bet is really asking help to regex to match the date format pattern and/or to do brute forcing.

Several years ago I wrote a little silly DateUtil class which did the job. Here's an extract of relevance:

private static final Map<String, String> DATE_FORMAT_REGEXPS = new HashMap<String, String>() {{
    put("^\\d{8}$", "yyyyMMdd");
    put("^\\d{1,2}-\\d{1,2}-\\d{4}$", "dd-MM-yyyy");
    put("^\\d{4}-\\d{1,2}-\\d{1,2}$", "yyyy-MM-dd");
    put("^\\d{1,2}/\\d{1,2}/\\d{4}$", "MM/dd/yyyy");
    put("^\\d{4}/\\d{1,2}/\\d{1,2}$", "yyyy/MM/dd");
    put("^\\d{1,2}\\s[a-z]{3}\\s\\d{4}$", "dd MMM yyyy");
    put("^\\d{1,2}\\s[a-z]{4,}\\s\\d{4}$", "dd MMMM yyyy");
    put("^\\d{12}$", "yyyyMMddHHmm");
    put("^\\d{8}\\s\\d{4}$", "yyyyMMdd HHmm");
    put("^\\d{1,2}-\\d{1,2}-\\d{4}\\s\\d{1,2}:\\d{2}$", "dd-MM-yyyy HH:mm");
    put("^\\d{4}-\\d{1,2}-\\d{1,2}\\s\\d{1,2}:\\d{2}$", "yyyy-MM-dd HH:mm");
    put("^\\d{1,2}/\\d{1,2}/\\d{4}\\s\\d{1,2}:\\d{2}$", "MM/dd/yyyy HH:mm");
    put("^\\d{4}/\\d{1,2}/\\d{1,2}\\s\\d{1,2}:\\d{2}$", "yyyy/MM/dd HH:mm");
    put("^\\d{1,2}\\s[a-z]{3}\\s\\d{4}\\s\\d{1,2}:\\d{2}$", "dd MMM yyyy HH:mm");
    put("^\\d{1,2}\\s[a-z]{4,}\\s\\d{4}\\s\\d{1,2}:\\d{2}$", "dd MMMM yyyy HH:mm");
    put("^\\d{14}$", "yyyyMMddHHmmss");
    put("^\\d{8}\\s\\d{6}$", "yyyyMMdd HHmmss");
    put("^\\d{1,2}-\\d{1,2}-\\d{4}\\s\\d{1,2}:\\d{2}:\\d{2}$", "dd-MM-yyyy HH:mm:ss");
    put("^\\d{4}-\\d{1,2}-\\d{1,2}\\s\\d{1,2}:\\d{2}:\\d{2}$", "yyyy-MM-dd HH:mm:ss");
    put("^\\d{1,2}/\\d{1,2}/\\d{4}\\s\\d{1,2}:\\d{2}:\\d{2}$", "MM/dd/yyyy HH:mm:ss");
    put("^\\d{4}/\\d{1,2}/\\d{1,2}\\s\\d{1,2}:\\d{2}:\\d{2}$", "yyyy/MM/dd HH:mm:ss");
    put("^\\d{1,2}\\s[a-z]{3}\\s\\d{4}\\s\\d{1,2}:\\d{2}:\\d{2}$", "dd MMM yyyy HH:mm:ss");
    put("^\\d{1,2}\\s[a-z]{4,}\\s\\d{4}\\s\\d{1,2}:\\d{2}:\\d{2}$", "dd MMMM yyyy HH:mm:ss");
}};

/**
 * Determine SimpleDateFormat pattern matching with the given date string. Returns null if
 * format is unknown. You can simply extend DateUtil with more formats if needed.
 * @param dateString The date string to determine the SimpleDateFormat pattern for.
 * @return The matching SimpleDateFormat pattern, or null if format is unknown.
 * @see SimpleDateFormat
 */
public static String determineDateFormat(String dateString) {
    for (String regexp : DATE_FORMAT_REGEXPS.keySet()) {
        if (dateString.toLowerCase().matches(regexp)) {
            return DATE_FORMAT_REGEXPS.get(regexp);
        }
    }
    return null; // Unknown format.
}

(cough, double brace initialization, cough, it was just to get it all to fit in 100 char max length ;) )

You can easily expand it yourself with new regex and dateformat patterns.

Sign up to request clarification or add additional context in comments.

14 Comments

What do you do with ambiguous dates? For example, what does 03/04/2010 mean - 3 April 2010 or 4 March 2010?
I guess assume one or the other (configurable)
@Jesper: the / separator is commonly used to denote MM/dd/yyyy (mainly used in US/English locales). The - separator is commonly used to denote dd-MM-yyyy (mainly used in European locales).
@Jesper yea you have to decide between a month or day with the format otherwise you'll never get anywhere.
@kittylyst: That's correct. Even more, there doesn't exist a bulletproof approach for this :)
|
52

There is a nice library called Natty which I think fits your purposes:

Natty is a natural language date parser written in Java. Given a date expression, natty will apply standard language recognition and translation techniques to produce a list of corresponding dates with optional parse and syntax information.

You can also try it online!

7 Comments

Wow! I am very impressed with this library's ability to parse any date in any format. It needs a little help with parsing times, however, I have addressed that in this post on SoftwareRecs.SE: softwarerecs.stackexchange.com/questions/26556/…
this is hands down the best library, I've even tried things like: "the day before christmas 2012" and it parsed it correctly
It fails with "13/02/2002", I get Feb 22, not very international it seems.
And fails with "2011-20-07"
Yes, amazingly Natty cannot handle day-month-year formats.
|
19

You could try dateparser.

It can recognize any String automatically, and parse it into Date, Calendar, LocalDateTime, OffsetDateTime correctly and quickly(1us~1.5us).

It doesn't based on any natural language analyzer or SimpleDateFormat or regex.Pattern.

With it, you don't have to prepare any appropriate patterns like yyyy-MM-dd'T'HH:mm:ss.SSSZ or yyyy-MM-dd'T'HH:mm:ss.SSSZZ:

Date date = DateParserUtils.parseDate("2015-04-29T10:15:00.500+0000");
Calendar calendar = DateParserUtils.parseCalendar("2015-04-29T10:15:00.500Z");
LocalDateTime dateTime = DateParserUtils.parseDateTime("2015-04-29 10:15:00.500 +00:00");

All works fine, please enjoy it.

3 Comments

Just had a look, it seems covering wide variety of formats
Works for my usecase
InputDate: "04/26/2022 12:00:00.000" - ExpectedDate: "04-26-2022" I just checked the README.md & saw the format I had was mentioned & was supported. Thanks. The following code saved my day: LocalDateTime localDateTime = DateParserUtils.parseDateTime("04/26/2022 12:00:00.000"); System.out.println("Parsed/Converted LocalDateTime form:: "+localDateTime.toString()); System.out.println("Target/Expected date:: "+DateTimeFormatter.ofPattern("MM-dd-yyyy").format(localDateTime));
7

What I have seen done is a Date util class that contains several typical date formats. So, when DateUtil.parse(date) is called, it tries to parse the date with each date format internally and only throws exceptions if none of the internal formats can parse it.

It is basically a brute force approach to your problem.

6 Comments

I think this is the most straight-forward and comprehensible approach. Since a date string of unknown format is ambigious by design, putting too much "intelligence" into the attempt to recognize the format probably results in more "surprising" results.
Yes, but I think there are a few assumptions you can make given a bit of starting information (order of day/month/year in a date) to correctly parse most sane dates without a big lookup table.
Max, that is true, and most likely there is a limited set of date formats that you would be looking for. You can make very few assumptions about the order of day and month without writing a full blown date parsing engine. Is there a specific use case for this, because that could help point people in the right direction. For example, most date formats from various social media services fit into about 10 popular formats.
Perhaps I'm more interested in the usability aspect. "Parse most dates without ever dealing with a format string again". I think I really just want to see a library like python-dateutil in Java, which I suppose would mean I should make it if I want it so bad!
I guess our definitions of usability are different too. The date class I had seen was able to parse dates from around 30 different web services. Using the date class was as simple as parse(date), so as a user of the utility I did not have to worry about date formats. The writer of the utility did the worrying for me.
|
1
//download library:   org.ocpsoft.prettytime.nlp.PrettyTimeParser
String str = "2020.03.03";
Date date = new PrettyTimeParser().parseSyntax(str).get(0).getDates().get(0);
System.out.println(date)

4 Comments

Please put your answer always in context instead of just pasting code. See here for more details.
@Mahdi is that prettytimeparser on the maven central? how we include it on our maven pom.xml?
2020.03.03 prints out "Thu Feb 18 20:20:03 CST 2021", that doesn't look right
@ennth yes. look at ocpsoft.org/prettytime/nlp
-3

I have no idea about this parsing how to do in python. In java we can do like this

SimpleDateFormat sdf1 = new SimpleDateFormat("dd-MM-yyyy");
  java.util.Date normalDate = null;
  java.sql.Date sqlDate = null;
  normalDate = sdf1.parse(date);
  sqlDate = new java.sql.Date(normalDate.getTime());
  System.out.println(sqlDate);

i think like java some predefined functions will be there in python. You can follow this method. This methods parse the String date to Sql Date (dd-MM-yyyy);

import java.text.SimpleDateFormat;
import java.text.ParseException;
public class HelloWorld{
     public static void main(String []args){
        String date ="26-12-2019";
         SimpleDateFormat sdf1 = new SimpleDateFormat("dd-MM-yyyy");
        java.util.Date normalDate = null;
        java.sql.Date sqlDate = null;
        if( !date.isEmpty()) {
            try {
                normalDate = sdf1.parse(date);
                sqlDate = new java.sql.Date(normalDate.getTime());
                System.out.println(sqlDate);
            } catch (ParseException e) {
            }
        }
     }
} 

execute this!

3 Comments

Please don’t teach the young ones to use the long outdated and notoriously troublesome SimpleDateFormat class. At least not as the first option. And not without any reservation. Today we have so much better in java.time, the modern Java date and time API, and its DateTimeFormatter.
If we know how to solve the problem, then we will look into the latest updates. Now we got a solution, we will try to get much better one. Anyways, thanks for your update!
This does not answer the question, as the poster asked how to automatically parse a date without having to specify a format. You're just showing a way to do it with format, and using outdated API as well.
-3

DateFormat formatter = new SimpleDateFormat("MM/dd/yy HH:mm:ss a"); formatter.setTimeZone(TimeZone.getTimeZone("America/New_York"));

3 Comments

welcome to Stack Overflow and thanks for wanting to contribute. I honestly don’t know what’s worst. (1) You are not answering the question. it’s about parsing practically any date format. Your code can be used to parse one format only. (2) No one should use DateFormat and SimpleDateFormat nor TimeZone. The first two are notoriously troublesome and the third has design problems too, and all three have been outdated for 10 years. Don’t use them and don’t help other users use them.
(3) Your code is incorrect. I parsed 11/28/99 12:45:00 AM, and since my time zone is 6 hours ahead of New York, I expected November 28, 1999, 06:45. But I got Sun Nov 28 18:45:00 CET 1999. 12 hours too far ahead. Minor point: once you have code that is worth sharing, please format it properly in your posts. Use the {} button above the edit field.
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.