开发者

SimpleDateFormat bug

 /**
 * Validates a date in String data type according to the given date format.
 * 
 * @param validDateFormat
 *           valid date format e.g. YYYY/MM/DD
 * @param strDate
 *            - the date to be validated
 * @return true if the date is valid according to the given format
 */
public static boolean isValidDate(final String strDate, final String validDateFormat) {
    boolean result = true;

    try {
        if (StringUtils.isNotBlank(validDateFormat) && StringUtils.isNotBlank(strDate)
                && StringUtils.isNotEmpty(strDate)) {
            dateValidator = new SimpleDateFormat(validDateFormat, Locale.ENGLISH);
            dateValidator.setLenient(false);
            dateValidator.parse(strDate);


            Log.i(TAG, "***Date entered: "+ strDate +
                    "\nDate parsed back: "+dateValidator.format(dateValidator.parse(strDate)));

            dateValidator = null;
        }
        else
        {
            result = false;
        }
    } catch (final ParseException e) {
        result = false;
    } catch (final IllegalArgum开发者_高级运维entException e) {
        result = false;
    } catch (final Exception e) {
        result = false;
    }

    return result;
}

When I input for example:

boolean result = isValidDate("21/May/201l", "dd/MMM/yyyy");
//result = true

be reminded that the input is not two-thousand-eleven, its two-hundred and one + a letter 'l'.

logs:

  ***Date entered: 21/May/201l
   Date parsed back: 21/May/0201

it doesn't throw any exception, and doesn't make it false!!!!

WHYYYYYYYYYY!?


Update: One idea would be to impose a rather severe restriction on your inputs: the input date string and format string must match exactly; you could enforce this by doing something like:

Date parsed = dateValidator.parse(strDate);
return strDate.equals(dateValidator.format(parsed));

In other words, verify that formatting the actual Date object returns a string that is identical to whatever was passed in. This ensures that you won't have erroneous positive results when there are actually invalid characters in the format string (since these will be ignored for the purposes of re-formatting the date).

I'm not sure it's a good solution in general, as it may be overly restrictive. I haven't really thought it through very carefully. But anyway, it's an idea.


From the documentation of DateFormat.parse (which is inherited by SimpleDateFormat):

The method may not use the entire text of the given string.

Also, from the "Throws" section of the same method:

ParseException - if the beginning of the specified string cannot be parsed.

Notice this: if I instantiate a SimpleDateFormat with the string "yyyy-MM-dd", then it will successfully parse the string "2011-05-12abcdefg":

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(format.parse("2011-05-12abcdefg"));

The above outputs (on my machine):

Thu May 12 00:00:00 CDT 2011

So basically it's just parsing as much as it can.

The fact that this is the behavior, even with setLenient(false), is indeed a bit strange to me.


You may have to create your own validator here. It will give back valid dates for trailing f and l due to how it casts numbers.

I suggest using the various iterations of String.indexOf to find the index positions of the "/" and then test the substrings. It should be pretty readily apparent as to how to validate the number portions of the date, at least. Your usage of Jan Feb Mar etc may complicate the middle validation ;)

Edited to your comment:

Something like - i cant see your question in edit mode, so bear with me here,

String day, month, year;
int div1, div2;
div1=yourDateString.indexOf("/");
div2=yourDateString.indexOf("/",div1);
day =yourDateString.substring(0,div1-1);
month =yourDateString.substring(div1+1,div2-1);
year =yourDateString.substring(div2+1,yourDateString.length()-1);

(I'm posting from my phone so I dont have full editor context and punctuation is a pain in the ass, so I hope you get the idea. this leaves you with individual strings of each field to test.)


One approach to do this is to use ParsePosition when parsing.

 `                        String d = "10/31/201lll";
                    ParsePosition pp = new ParsePosition(0);
                    SimpleDateFormat sdf = new SimpleDateFormat("mm/dd/yyyy");
                    sdf.setLenient(false);

                    try {
                            System.out.println(sdf.parse(d, pp));
                            System.out.println(pp.getIndex());
                            System.out.println(d.length());
                    }
                    catch(Exception e){
                            e.printStackTrace();
                    }

`

The parsePosition.getIndex() gives you the index of the character after the last character that was used for parsing. Comparing this to the length of your input string should tell you if this was an absolute parse or a partial parse.


The reason that that is happening, I believe, is because a ### + the letter l at the end is a valid number in Java. The 'l' indicates that the value is a long integer. So, the year you are posting is really May 21, 201, and Java handles the letter. (Try switching it to an m or something and it should break.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜