Java SimpleDateFormat Parse Wrong Date

2019-01-20 15:20发布

I'm trying to use the parse function of SimpleDateFormat to turn a String into a Date

    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-YYYY");

    String strInput1 = "29-04-2014";
    System.out.println("string 1: " + strInput1);

    Date date1 = new Date();
    try {
        date1 = sdf.parse(strInput1);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    System.out.println("date 1: " + date1.toString());

    String strInput2 = sdf.format(date1);
    System.out.println("string 2: " +strInput2);

    Date date2 = new Date();
    try {
        date2 = sdf.parse(strInput2);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    System.out.println("date 2 " + date2);

The output for date1 is Mon Dec 30 00:00:00 GMT 2013, which is then correctly parsed to 30-12-2014.

I assume the mistake is somewhere when sdf is initialized.

2条回答
不美不萌又怎样
2楼-- · 2019-01-20 15:34

You're using YYYY which is the week year. You mean yyyy, which is the year.

Just change your format to:

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

The YYYY format specifier is rarely used, and when it is used, it should be used in conjunction with E/u (day of week name/number) and w (week of week year).

Note that you should consider setting the time zone of your SimpleDateFormat as well... additionally, if you're using Java 8, use the java.time package, and otherwise Joda Time is a much cleaner library than java.util.Date etc.

查看更多
Ridiculous、
3楼-- · 2019-01-20 15:38

The modern Java data & time API defined in JSR-310 came out just about the time this question was asked, so I thought it was about time for an answer using it. For the sake of the example and explanation, let’s try keeping your incorrect format pattern string at first:

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MM-YYYY");

    String strInput1 = "29-04-2014";
    System.out.println("string 1: " + strInput1);

    LocalDate date1 = LocalDate.parse(strInput1, dtf);

    System.out.println("date 1: " + date1.toString());

The attempt to parse strInput1 gives java.time.format.DateTimeParseException: Text '29-04-2014' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {DayOfMonth=29, MonthOfYear=4, WeekBasedYear[WeekFields[SUNDAY,1]]=2014},ISO of type java.time.format.Parsed. On one hand I consider the exception a step forward compared to just yielding an incorrect date, as you experienced. On the other hand the exception message is not that easy to read without a deeper knowledge of the newer classes. The word to notice is “WeekBasedYear”. This is only useful with week numbers, so take it as a sign of what’s wrong. Then compare with the documentation. It says that u is for year, lowercase y is for year-of-era and uppercase Y is for week-based year. Assuming year will always be in the common era (“anno domini”), we can take u or y:

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MM-uuuu");

Now the code prints:

string 1: 29-04-2014
date 1: 2014-04-29

We can also format the date back into a string, of course:

    String strInput2 = date1.format(dtf);
    System.out.println("string 2: " +strInput2);

The result is the string we started out from, as expected:

string 2: 29-04-2014

Note that the modern API comes with a LocalDate class for a date without time of day. This models your requirement more precisely in this case and avoids all kinds of corner cases that might come out of having to drag the time of day along in a Date object.

Question: can I use this with Java 7? You certainly can. For Java 6 and 7 get the ThreeTen Backport and start using the modern classes.

查看更多
登录 后发表回答