Arun Francis
Arun Francis

Reputation: 25

SimpleDateFormat not working properly

I have the following code in my program that converts the given date into different date formats.

public static final List < SimpleDateFormat > dateFormats = new ArrayList < SimpleDateFormat > () {
    {
        add(new SimpleDateFormat("M/dd/yyyy"));
        add(new SimpleDateFormat("dd.M.yyyy"));
        add(new SimpleDateFormat("dd.MMM.yyyy"));
        add(new SimpleDateFormat("dd-MMM-yyyy"));
        add(new SimpleDateFormat("yyyy-MM-dd"));
        add(new SimpleDateFormat("M/dd/yyyy HH:mm"));
        add(new SimpleDateFormat("dd.M.yyyy HH:mm"));
        add(new SimpleDateFormat("dd.MMM.yyyy HH:mm"));
        add(new SimpleDateFormat("dd-MMM-yyyy HH:mm"));
        add(new SimpleDateFormat("yyyy-MM-dd HH:mm"));
    }
};

public static Date convertToDate(String input) {
    Date date = null;
    if (null == input) {
        return null;
    }
    for (SimpleDateFormat format: dateFormats) {
        try {
            format.setLenient(false);
            date = format.parse(input);
        } catch (ParseException e) {}
        if (date != null) {
            break;
        }
    }

    return date;
}

But on running the above code once the date format is changed, the time is getting reseted to zero. Whats the issue here??

Upvotes: 2

Views: 2302

Answers (3)

Bohemian
Bohemian

Reputation: 424973

I can't say for sure this is your problem, but I can say fit sure your code is not threadsafe, because SimpleDateFormat is not threadsafe.

If this code is used by an HttpRequestHandler to handle web requests for example, you will get unpredictable behaviour - including perhaps what you are seeing.

The safest approach is to store the formats (Strings) in an array and create the SimpleDateFormat objects as you need them

Upvotes: 0

Himanshu
Himanshu

Reputation: 517

I guess you are saying that when you pass a input like 1/11/12 13:14 your time is reset to zero if thats the case just reorder your stack of formats

public static final List<DateFormat> dateFormats = new ArrayList<DateFormat>()
{
    {
        add(new SimpleDateFormat("M/dd/yyyy HH:mm"));
        add(new SimpleDateFormat("dd.M.yyyy HH:mm"));
        add(new SimpleDateFormat("dd.MMM.yyyy HH:mm"));
        add(new SimpleDateFormat("dd-MMM-yyyy HH:mm"));
        add(new SimpleDateFormat("yyyy-MM-dd HH:mm"));
        add(new SimpleDateFormat("M/dd/yyyy"));
        add(new SimpleDateFormat("dd.M.yyyy"));
        add(new SimpleDateFormat("dd.MMM.yyyy"));
        add(new SimpleDateFormat("dd-MMM-yyyy"));
        add(new SimpleDateFormat("yyyy-MM-dd"));
    }
};

to

public static final List<SimpleDateFormat> dateFormats = new ArrayList<SimpleDateFormat>()
    {
      {
        add(new SimpleDateFormat("M/dd/yyyy HH:mm"));
        add(new SimpleDateFormat("dd.M.yyyy HH:mm"));
        add(new SimpleDateFormat("dd.MMM.yyyy HH:mm"));
        add(new SimpleDateFormat("dd-MMM-yyyy HH:mm"));
        add(new SimpleDateFormat("yyyy-MM-dd HH:mm"));
        add(new SimpleDateFormat("M/dd/yyyy"));
        add(new SimpleDateFormat("dd.M.yyyy"));
        add(new SimpleDateFormat("dd.MMM.yyyy"));
        add(new SimpleDateFormat("dd-MMM-yyyy"));
        add(new SimpleDateFormat("yyyy-MM-dd"));
      }
    };

use time based patterns first and then use only date based patterns, I guess you get a successful match for a date based pattern and an output is returned giving you time as 0

Upvotes: 0

Elliott Frisch
Elliott Frisch

Reputation: 201409

Your indentation was a bit off, you shouldn't use Raw Types and to answer your question you need to test formats with time before formats without time (if you want to keep the parsed time).

public static final List<DateFormat> dateFormats = new ArrayList<DateFormat>()
{
    {
        add(new SimpleDateFormat("M/dd/yyyy HH:mm"));
        add(new SimpleDateFormat("dd.M.yyyy HH:mm"));
        add(new SimpleDateFormat("dd.MMM.yyyy HH:mm"));
        add(new SimpleDateFormat("dd-MMM-yyyy HH:mm"));
        add(new SimpleDateFormat("yyyy-MM-dd HH:mm"));
        add(new SimpleDateFormat("M/dd/yyyy"));
        add(new SimpleDateFormat("dd.M.yyyy"));
        add(new SimpleDateFormat("dd.MMM.yyyy"));
        add(new SimpleDateFormat("dd-MMM-yyyy"));
        add(new SimpleDateFormat("yyyy-MM-dd"));
    }
};

Finally, I suggest you just return the first time you successfully parse (instead of breaking out of the loop later) -

public static Date convertToDate(String input) {
    if (input == null) {
        return null;
    }
    for (SimpleDateFormat format : dateFormats) {
        try {
            format.setLenient(false);
            return format.parse(input);
        } catch (ParseException e) {
        }
    }    
    return null; // <-- nothing parsed.
}

Edit

Also, as Bohemian noted here; if you're using multiple threads you should use the String format to recreate the DateFormat because SimpleDateFormat isn't thread safe.

public static final String[] dateFormats = { "M/dd/yyyy HH:mm",
        "dd.M.yyyy HH:mm", "dd.MMM.yyyy HH:mm", "dd-MMM-yyyy HH:mm",
        "yyyy-MM-dd HH:mm", "M/dd/yyyy", "dd.M.yyyy", "dd.MMM.yyyy",
        "dd-MMM-yyyy", "yyyy-MM-dd" };

public static Date convertToDate(String input) {
    Date date = null;
    if (null == input) {
        return null;
    }
    for (String fmt : dateFormats) {
        try {
            DateFormat format = new SimpleDateFormat(fmt);
            format.setLenient(false);
            date = format.parse(input);
            break;
        } catch (ParseException e) {
        }
    }
    return date;
}

Upvotes: 1

Related Questions