javadatetimesimpledateformatjava.util.calendar

Why Calendar and SimpleDateFormat are showing a bad date?


I try to parse a date from a string but when I print it, it shows a bad date. My code:

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.text.SimpleDateFormat;

public class Main {
    public static void main(String args[]) {
        String some_date = "2017-12-31";
        Calendar cal_aux = GregorianCalendar.getInstance();
        System.out.println("set calendar: " + Integer.parseInt(some_date.substring(0, 4))
                + Integer.parseInt(some_date.substring(5, 7))
                + Integer.parseInt(some_date.substring(8, 10)));
        cal_aux.set(Integer.parseInt(some_date.substring(0, 4)),
                Integer.parseInt(some_date.substring(5, 7)),
                Integer.parseInt(some_date.substring(8, 10)));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("sdf calendar: " + sdf.format(cal_aux.getTime()));
    }
}

Console output:

set calendar: 20171231
sdf calendar: 2018-01-31 12:51:02

Why when I use the simple date format I'm getting 2018 instead of 2017?


Solution

  • Avoid the legacy date-time classes now supplanted by java.time classes. The problematic legacy classes have many design faults. One such fault is counting months as 0-11 rather than 1-12. This crazy counting is breaking your code.

    Do not manipulate date-time values as strings. Use objects.

    For that date-only value use LocalDate.

    LocalDate ld = LocalDate.parse( "2017-12-31" )  ;  // Or LocalDate.now() for today's date.
    

    Generate a String by using a DateTimeFormatter.

    String output = ld.format( DateTimeFormatter.BASIC_ISO_DATE ) ;
    

    20171231

    Assign a time-of-day if desired.

    LocalTime lt = LocalTime.of( 6 , 15 ) ;
    LocalDateTime ltd = LocalDateTime.of( ld , lt ) ;
    

    Apply a time zone if you want an actual moment, a specific point on the timeline.

    ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;
    ZonedDateTime zdt = ldt.atZone( z ) ;