sathish
sathish

Reputation: 1395

How to get the given date string format(pattern) in java?

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?

Upvotes: 49

Views: 120877

Answers (10)

Anonymous
Anonymous

Reputation: 86276

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

Upvotes: 1

Vinit Solanki
Vinit Solanki

Reputation: 2023

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.

Upvotes: 1

sulin
sulin

Reputation: 398

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.

Upvotes: 1

Madhu
Madhu

Reputation: 624

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) {

                }
            }
        }
    }
}

Upvotes: 60

Ravi
Ravi

Reputation: 63

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

Upvotes: 2

saad
saad

Reputation: 1

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,})

Upvotes: -3

Pratik
Pratik

Reputation: 30855

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

Upvotes: 10

michael667
michael667

Reputation: 3260

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.

Upvotes: 2

Piotr Gwiazda
Piotr Gwiazda

Reputation: 12212

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.

Upvotes: 3

Buhake Sindi
Buhake Sindi

Reputation: 89169

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.

Upvotes: 0

Related Questions