-4

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?

Franco Morero
  • 549
  • 5
  • 20
  • What results are you expecting? If you want cal_aux to not have the current time, then see the java doc for the 'set' method at https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#set(int,%20int,%20int) which says "Previous values of other calendar fields are retained. If this is not desired, call clear() first." – racraman Nov 07 '17 at 21:34
  • 2
    Please edit your question into English, and provide a [mcve]. (Or alternatively, find the most appropriate non-English Stack Overflow site, of course - https://es.stackoverflow.com perhaps?) – Jon Skeet Nov 07 '17 at 21:36
  • 1
    You forgot to subtract 1 from the month value. Your input month is `12`, meaning December, but the **javadoc** of [`Calendar.set()`](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#set-int-int-int-) says *"`month` - the value used to set the MONTH calendar field. Month value is **0-based. e.g., 0 for January**."* This is a common pitfall of `Calendar` and you're the latest victim. – Andreas Nov 07 '17 at 21:41
  • 1
    Duplicate of [Incorect Date to String convertation in Java](https://stackoverflow.com/q/32284908/5221149). – Andreas Nov 07 '17 at 21:44
  • 2
    I'm voting to close this question as off-topic because it is not written in English. – Basil Bourque Nov 08 '17 at 01:10
  • 1
    You are using troublesome classes that are now legacy, supplanted by the java.time classes. – Basil Bourque Nov 08 '17 at 01:11
  • 1
    @BasilBourque is correct. Furthermore, as far as I can tell, using [the modern Java date and time API known as `java.time` or JSR-310](https://docs.oracle.com/javase/tutorial/datetime/) will immediately free you from issues like the one you are asking about. – Ole V.V. Nov 08 '17 at 13:20

2 Answers2

2

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 ) ;
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • 1
    The other thing that went wrong with the `Calendar` class is that even though its months are 0 through 11, it still accepts 12 as a month value and just takes it to mean January in the following year. Quite surprising to most, and most often negatively. – Ole V.V. Nov 09 '17 at 08:42
1

First, you set wrong date because the month range is 0-11. When you set 12 in month field, is january 2018 instead december 2017.

Second, you can simplify your program parsing the input string to formatted date and parsing this date to output formatted string. Here is an example:

String input = "20171231";
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyyMMdd");
SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

try {
    System.out.println(outputFormat.format(inputFormat.parse(input)));
} catch (ParseException e) {
    // Log error
}