0

I try to parse date string but always get wrong month. Here's my code.

This is code to select date from calender

@OnClick(R.id.tedit_tgllahir_addnew) void showTimeDialog(){
        calendar = Calendar.getInstance();
        year = calendar.get(Calendar.YEAR);
        month = calendar.get(Calendar.MONTH);
        date = calendar.get(Calendar.DAY_OF_MONTH);
        DatePickerDialog datePickerDialog = new DatePickerDialog(AddDataForNewUserActivity.this,
                new DatePickerDialog.OnDateSetListener() {
                    @Override
                    public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
                        etTgl.setText(String.format("%02d/%02d/%02d", year, month+1, dayOfMonth));
                    }

                }, year, month, date);

        datePickerDialog.show();
    }

and this is when i want to parse data

birth = LocalDate.of(list.getTglLahirAnak().getYear() + 1900, list.getTglLahirAnak().getMonth(), list.getTglLahirAnak().getDate());
                        int year =  Period.between(birth, LocalDate.now()).getYears();
                        int month = Period.between(birth, LocalDate.now()).getMonths();
                        int totalBulan = year * 12 + month;

Whenever I input date from the calender, it always shows the wrong month. For example I choose May but in the system read April. Thanks to all who are willing to help.

Ole V.V.
  • 65,573
  • 11
  • 96
  • 117
Tiramochi
  • 1
  • 1
  • 2
    I recommend you neither use `Calendar` nor `Date`. Both classes are poorly designed and long outdated. Just stay with `LocalDate` and `Period` from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Jul 24 '20 at 06:43
  • Does this answer your question? [Convert java.util.Date to java.time.LocalDate](https://stackoverflow.com/questions/21242110/convert-java-util-date-to-java-time-localdate). The comments under [this answer](https://stackoverflow.com/a/26597701/5772882) are relevant when using ThreeTenABP. – Ole V.V. Jul 24 '20 at 06:44
  • I wrote a quick [new answer for you here](https://stackoverflow.com/a/63068341/5772882). – Ole V.V. Jul 24 '20 at 06:54
  • As an aside it seems that you can use [`Period.toTotalMonths()`](https://docs.oracle.com/javase/10/docs/api/java/time/Period.html#toTotalMonths()) to your advantage. – Ole V.V. Jul 24 '20 at 07:18
  • Or does this answer your question? [SimpleDateFormat. format returning wrong date](https://stackoverflow.com/questions/55395261/simpledateformat-format-returning-wrong-date) – Ole V.V. Jul 24 '20 at 07:38

1 Answers1

1

I gather from your question that you are using the backport of JSR-310, probably the Android edition, ThreeTenABP. If so, go all-in on that and drop the use of the poorly designed and long outdated Calendar and Date classes.

Even if the use of the Date class is dictated from outside of your control, you must still stay away from its deprecated methods including getYear(), getMonth() and getDate(). You are trying the good thing when receiving a Date and converting it to a LocalDate first thing. Use DateTimeUtils from the backport for a first conversion.

But let’s take it from the top. Use LocalDate for setting the initial date of your date picker. Don’t use the old-fashioned Calendar class. I have not compiled the code, so please forgive if there’s a typo.

    LocalDate today = LocalDate.now(ZoneId.systemDefault());
    year = today.getYear();
    month = today.getMonthValue(); // naturally 1-based
    date = today.getDayOfMonth();
    DatePickerDialog datePickerDialog = new DatePickerDialog(AddDataForNewUserActivity.this,
            new DatePickerDialog.OnDateSetListener() {
                @Override
                public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
                    // will return to this part later
                }

            }, year, month - 1, date); // Pass 0-based month

When the user selects a date from the calendar/date picker, don’t store it as a string. Store it as a LocalDate object. This saves you from doing any parsing later, and your code also shows that you need a LocalDate. Obviously if you want to show the selected date to the user, format the date into a string for that purpose (only). Use a DateTimeFormatter for formatting:

private static final DateTimeFormatter dateFormatter
        = DateTimeFormatter.ofPattern("yy/MM/dd");

Now we go:

                @Override
                public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
                    // Store the selected date somewhere you can find it later
                    selectedLocalDate = LocalDate.of(year, month + 1, dayOfMonth);
                    // Display to the user
                    String formattedDate = selectedLocalDate.format(dateFormatter);
                    etTgl.setText(formattedDate);
                }

Now the calculation of age in months poses no problem anymore:

    birth = selectedLocalDate;
    long totalBulan = Period.between(birth, LocalDate.now(ZoneId.systemDefault()))
                           .toTotalMonths();

If you cannot control what you get from list.getTglLahirAnak(), the conversion from Date to LocalDate is:

    Date oldfashionedDate = list.getTglLahirAnak();
    birth = DateTimeUtils.toInstant(oldfashionedDate)
        .atZone(ZoneId.systemDefault())
        .toLocalDate();

Now the calculation of age proceeds as before.

What went wrong in your code?

Just like the outdated Calendar also the deprecated Date.getMonth() numbers the months from 0 for January through 11 for December. So if you pick a date in May, list.getTglLahirAnak().getMonth() returns 4 for May. When you feed this into a LocalDate with its natural and sensible month numbering, it gives you April.

Ole V.V.
  • 65,573
  • 11
  • 96
  • 117