47

I want to get the format of a given date string.

Example: I have a string like 2011-09-27T07:04:21.97-05:00 and the date format of this string is yyyy-MM-dd'T'HH:mm:ss.SSS.

Here I want to find out this date format when I pass string(2011-09-27T07:04:21.97-05:00) to a method which will return the format(yyyy-MM-dd'T'HH:mm:ss.SSS), then later I will format my given date string according to my requirement(like yy-mm--dd or mm/dd/yyyy).

Can any one tell me how can I get it achieved?

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
sathish
  • 1,375
  • 6
  • 17
  • 31

10 Answers10

59
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NewClass {

    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",        "yyyyMMdd", };

        /*
         * @param args
         */
    public static void main(String[] args) {
        String yyyyMMdd = "20110917";   
        parse(yyyyMMdd);
    }

    public static void parse(String d) {
        if (d != null) {
            for (String parse : formats) {
                SimpleDateFormat sdf = new SimpleDateFormat(parse);
                try {
                    sdf.parse(d);
                    System.out.println("Printing the value of " + parse);
                } catch (ParseException e) {

                }
            }
        }
    }
}
Alex Essilfie
  • 12,339
  • 9
  • 70
  • 108
Madhu
  • 614
  • 5
  • 2
  • 1
    Above solution will parse Date for sure but will not give date format. SimpleDateFormat's toPattern & toLocalizedPattern will give the exact format. – Vikas Chowdhury Jun 02 '16 at 10:00
  • If someone is using this solution, just simply return the parse string after printing the value – Narasimha Sep 28 '17 at 19:53
  • Never hardcode `Z` as a literal in your format pattern. It’s an offset and needs to be parsed as such, or you get incorrect results. And a 2020 comment: We should no longer use `Date` and `SimpleDateFormat`. Those classes are poorly designed and long outdated. – Ole V.V. Jul 04 '20 at 06:19
10

you can do like this way, I don't know good way or not but try this

first create the SimpleDateFormat object

SimpleDateFormt sdf = new SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSS");

now when check the date if this will parse in this format then change as per your format

try{
     Date date = sdf.parse(yourdate);
     sdf.applyPattern("yy-mm--dd or mm/dd/yyyy");
     String dateformat = sdf.format(date);
}catch(Exception ex) { // here forgot the exact exception class Parse exception was used
    // do something here
}

updated post:

Returning a date format from an unknown format of date string in java

How to convert String to Date without knowing the format?

Parse any date in Java

Community
  • 1
  • 1
Pratik
  • 30,639
  • 18
  • 84
  • 159
  • 2
    how can i specify the format to SimpleDateFormat with out knowing given string format? – sathish Sep 28 '11 at 06:59
  • how can i specify the format to SimpleDateFormat as "yyyy-mm-dd 'T' HH:mm:ss.SSS" with out knowing given string format? if my string is like 2011-09-28 12:00:22 then how should i parse this with above SimpleDateFormat object? – sathish Sep 28 '11 at 08:52
3

I think you should try to parse input string with some predefine patterns. The one that works is the one you need. Remember that some patterns are quite tricky.

01.12.12 is 01 December 2012 in Europe but 12 January 2012 in USA. It could be 12 December 2001 too.

Piotr Gwiazda
  • 12,080
  • 13
  • 60
  • 91
2

Madhu's code is can workout, but some performance problem will arise because every failure case will raise the exception. i think we need to find the reguler expression solution to find the pattern form the given date String.

you can find all most all reg expressions to date and time format in the following link

http://regexlib.com/DisplayPatterns.aspx?cattabindex=4&categoryId=5&AspxAutoDetectCookieSupport=1

Ravi
  • 63
  • 1
  • 8
2

If I understand you correctly, you want to parse arbitrary strings (that is, string of a format you don't know) as dates by using DateFormat.parse()? Then you have to deal with issues like how to handle 01-02-03 (2 Jan 2003? 1 Feb 2003? etc.)

You should know at least something about the expected format, like a choice of several predefined formats for your input.

michael667
  • 3,241
  • 24
  • 32
1

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'Z' or MM/dd/yyyy HH:mm:ss etc:

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");

And it has better performance than loop-try multiple SimpleDateFormat.

Please enjoy it.

sulin
  • 358
  • 5
  • 7
1

Here is a generic solution the determine the pattern without knowing the date pattern in advance and without calling the parse method of SimpleDateFormat for all formats. You can get any date pattern from date string value by using the regex.

package com.utility.utils.modelmapper.datetime;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class DateParser {
    private static final Map<String, String> DATE_FORMAT_REGEXPS = new HashMap<String, String>() {
        {
            put("^\\d{8}$", "yyyyMMdd");
            put("^\\d{12}$", "yyyyMMddHHmm");
            put("^\\d{8}\\s\\d{4}$", "yyyyMMdd HHmm");
            put("^\\d{14}$", "yyyyMMddHHmmss");
            put("^\\d{8}\\s\\d{6}$", "yyyyMMdd HHmmss");
            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{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{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");
            put("^\\d{4}-\\d{1,2}-\\d{1,2}T\\d{1,2}:\\d{2}:\\d{2}\\.\\d{2}[-+]\\d{2}:\\d{2}$", "yyyy-MM-dd'T'HH:mm:ss.SSS");
        }
    };

    /**
     * To Determine the pattern by the string date value
     * 
     * @param dateString
     * @return The matching SimpleDateFormat pattern, or null if format is unknown.
     */
    public static String determineDateFormat(String dateString) {
        for (String regexp : DATE_FORMAT_REGEXPS.keySet()) {
            if (dateString.matches(regexp) || dateString.toLowerCase().matches(regexp)) {
                return DATE_FORMAT_REGEXPS.get(regexp);
            }
        }
        return null;
    }

    public static void main(String[] args) {
        parse("2011-09-27T07:04:21.97-05:00"); //here is your value
        parse("20110917");
        parse("01/02/2018");
        parse("02-01-2018 06:07:59");
        parse("02 January 2018");
    }

    public static void parse(String value) {
        if (value != null) {
            String format = determineDateFormat(value);
            if (format != null) {
                SimpleDateFormat sdf = new SimpleDateFormat(format);
                try {
                    Date date = sdf.parse(value);
                    System.out.println(String.format("Format : %s | Value : %s | Parsed Date : %s", value, date, format));
                } catch (ParseException e) {
                    // Failed the execution
                }
            }
        }
    }
}

Console output of the class:

Format : 2011-09-27T07:04:21.97-05:00 | Value : Tue Sep 27 07:04:21 LINT 2011 | Parsed Date : yyyy-MM-dd'T'HH:mm:ss.SSS
Format : 20110917 | Value : Sat Sep 17 00:00:00 LINT 2011 | Parsed Date : yyyyMMdd
Format : 01/02/2018 | Value : Tue Jan 02 00:00:00 LINT 2018 | Parsed Date : MM/dd/yyyy
Format : 02-01-2018 06:07:59 | Value : Tue Jan 02 06:07:59 LINT 2018 | Parsed Date : dd-MM-yyyy HH:mm:ss
Format : 02 January 2018 | Value : Tue Jan 02 00:00:00 LINT 2018 | Parsed Date : dd MMMM yyyy

Maybe I missed some of the date-time patterns here but for that the correct regex pattern should be added in the map.

Vinit Solanki
  • 1,863
  • 2
  • 15
  • 29
  • 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,](https://docs.oracle.com/javase/tutorial/datetime/) and its `DateTimeFormatter`. Otherwise this is a creative solution. – Ole V.V. Jul 01 '20 at 02:59
  • 1
    This example is not about to show how `SimpleDateFormat` would work, but see the question it's about the get the date pattern, I just used `SimpleDateFormat` to show its actually getting correct pattern, after getting the correct pattern use whatever you would like. – Vinit Solanki Jul 01 '20 at 03:21
  • 1
    Also [Don’t be “Clever”: The Double Curly Braces Anti Pattern](https://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/) – Ole V.V. Jul 01 '20 at 03:41
  • I guess that would be a separate topic to use the "Doubly Curly Braces Anti-pattern" or not. – Vinit Solanki Jul 01 '20 at 04:09
  • You are perfectly entitled to your opinion, obviously. My opinion is that when you post an answer that includes two bad practices without mentioning that they are bad practices, you run a great risk of leading readers astray rather than helping them. – Ole V.V. Jul 01 '20 at 05:26
  • you are correct on we should avoid the SimpleDateFormat & Doubly Curly brackets but I am saying the post or answer gives you an idea, hint or solution but not the full code which you directly copy from here and directly paste into the project. The user of the code should get this hint or idea from the answers and the rest of think user should explore their self. And one more thing why you don't come up with the your suggestion here that you are taking in this comments. – Vinit Solanki Jul 01 '20 at 06:55
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/216999/discussion-between-ole-v-v-and-vinit-solanki). – Ole V.V. Jul 01 '20 at 07:01
0

java.time and its predefined formatters

We cannot do this for just any date-time format. There are thousands of them, we cannot know them all (someone will invent a new one tomorrow), and some look alike so much we can’t tell which we’ve got.

I suggest that for the majority of purposes you need to parse the string, but you don’t need to know a format pattern for doing so. In very many cases, including the example from your question, 2011-09-27T07:04:21.97-05:00, we don’t need to specify a pattern (your string matches DateTimeFormatter.ISO_OFFSET_DATE_TIME).

Since Java 8 came out in 2014 (and even if still using Java 6 or 7), use java.time, the modern Java date and time API, for your date and time work.

I am defining an array of formatters for the formats we want to cater for. Please substitute your own set.

private static final DateTimeFormatter[] formatters = {
        DateTimeFormatter.ISO_OFFSET_DATE_TIME,
        DateTimeFormatter.RFC_1123_DATE_TIME,
        new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_LOCAL_DATE)
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
                .toFormatter(),
        DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).withLocale(Locale.US),
        DateTimeFormatter.ofPattern("MM/dd/uuuu HH:mm")
                .withZone(ZoneId.of("America/Los_Angeles"))
};

The following method tries the formatters in turn until one works:

private static OffsetDateTime parse(String dateTimeString) {
    for (DateTimeFormatter formatter : formatters) {
        try {
            return ZonedDateTime.parse(dateTimeString, formatter)
                    .toOffsetDateTime();
        } catch (DateTimeParseException dtpe) {
            // Ignore, try next formatter
        }
    }
    throw new IllegalArgumentException("String " + dateTimeString + " could not be parsed");
} 

Let’s try it out with some different strings:

    String[] dateTimeStrings = {
            "2011-09-27T07:04:21.97-05:00",
            "20110917",
            "2012-07-04",
            "12/27/2014 23:45",
            "Mon, 12 Nov 2018 01:32:10 GMT",
            "July 29, 2015 at 10:19:36 AM EDT",
    };
    
    for (String dts : dateTimeStrings) {
        try {
            System.out.format("%32s -> %s%n", dts, parse(dts));
        } catch (IllegalArgumentException iae) {
            System.out.format("%32s -> %s%n", dts, iae);
        }
    }

Output is:

    2011-09-27T07:04:21.97-05:00 -> 2011-09-27T07:04:21.970-05:00
                        20110917 -> java.lang.IllegalArgumentException: String 20110917 could not be parsed
                      2012-07-04 -> 2012-07-04T00:00Z
                12/27/2014 23:45 -> 2014-12-27T23:45-08:00
   Mon, 12 Nov 2018 01:32:10 GMT -> 2018-11-12T01:32:10Z
July 29, 2015 at 10:19:36 AM EDT -> 2015-07-29T10:19:36-04:00

Other options

Techniques for parsing dates and times in multiple formats include:

  • Take a taste of the string to decide its format and use an appropriate formatter based on that. It’s best suited if you have just a few formats, though the answer by Vinit Solanki shows an elaborate version for quite many formats.
  • Use optional parts in a format pattern string. For example [uuuu][uu] will parse either four digit or two digit year (2021 or just 21).
  • Try several formatters in turn as shown in my code above. If you do need to know the pattern, use an array of patterns instead of an array of formatters.
  • Requiring the supplier of the string to supply a format patterns string too. This is not always as simple as it may sound, though.

Beware of ambiguity. The classical example is the two formats MM-dd-yyyy and dd-MM-yyyy. If we get a string of 03-09-2020, there’s no way to tell whether it means March 9 or 3rd September. Even worse, 02-05-07 might be yy-MM-dd, dd-MM-yy, MM-dd-yy and even more possibilities. As a consequence, make sure you don’t include two (or more) formatters that may parse the same string into different results.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

You will need to take the inital date string and covert it to a date object and pass that converted date object and format it to your required string.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
-3
HH:mm:ss.SSS => ([0-2]{1,}[0-9]{1,})(:)([0-5]{1,}[0-9]{1,})(:)([0-5]{1,}[0-9]{1,})(.)([0-9]{1,3})

yyyy-mm-dd => ([0-9]{4})(-)([0-1]{1,}[0-9]{1,})(-)([0-3]{1,}[0-9]{1,})
John Conde
  • 217,595
  • 99
  • 455
  • 496
saad
  • 1