javaandroiddatematerialdatepicker

Turn the long generated by MaterialDatePicker into year, month, and day varialbes


I am using the following code:

MaterialDatePicker.Builder<Long> datePickerBuilder = MaterialDatePicker.Builder.datePicker();
MaterialDatePicker<Long> datePicker = datePickerBuilder.build();
datePicker.addOnPositiveButtonClickListener(selection -> {
    Date selectedDate = Calendar.getInstance().getTime();
    selectedDate.setTime(selection);

    // Return and set the text of the date edit text.
    TextInputEditText inputDateEditText = dialogView.findViewById(R.id.input_date_edit_text);

    // Set temp variables accordingly.
    LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(selection), ZoneId.systemDefault());

    int year = dateTime.getYear();
    int month = dateTime.getMonthValue();
    int day = dateTime.getDayOfMonth();

    // Get formatted month name.
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.MONTH, month + 1);
    SimpleDateFormat monthDate = new SimpleDateFormat("MMM", Locale.getDefault()); // Use MMMM for full name of month.
    String monthName = monthDate.format(cal.getTime());

    // Put the text into the edittext.
    inputDateEditText.setText("" + monthName + " " + day + ", " + year);

    // Set variables accordingly.
    newEventSelectedYear.set(year);
    newEventSelectedMonth.set(month);
    newEventSelectedDay.set(day);

    System.out.println(selection);
});
datePicker.show(getFragmentManager(), "DATE_PICKER");

I'm trying to use MaterialDatePicker<Long> to display a date picker and then put the values it receives from the user into the newEventSelected... variables. I need the month value to be zero-based (so October is month 9) and all the other values to be one-based (so if the user selects "October 20, 2023" in the dialog, the year will be recorded as 2023, month as 9, and the day as 20.

If it helps, I was using the following code, (which worked) before:

DatePickerDialog datePickerDialog = new DatePickerDialog(requireContext());
datePickerDialog.setOnDateSetListener((view12, year, month, dayOfMonth) -> {
    // Return and set the text of the date edit text.
    TextInputEditText inputDateEditText = dialogView.findViewById(R.id.input_date_edit_text);

    // Get formatted month name.
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.MONTH, month);
    SimpleDateFormat monthDate = new SimpleDateFormat("MMM", Locale.getDefault()); // Use MMMM for full name of month.
    String monthName = monthDate.format(cal.getTime());

    // Put the text into the edittext.
    inputDateEditText.setText("" + monthName + " " + dayOfMonth + ", " + year);

    // Set variables accordingly.
    newEventSelectedYear.set(year);
    newEventSelectedMonth.set(month);
    newEventSelectedDay.set(dayOfMonth);
});
datePickerDialog.show();

But I had to switch to MaterialDatePicker because DatePickerDialog's interface didn't match my app's.

How do I do this?

Edit:

I looked at this question, which was recommended to me by @commonsware, but had a few questions:

Instant instant = Instant.ofEpochMilli(selection);
System.out.println(instant);

OffsetDateTime odt = instant.atOffset(ZoneOffset.of("-04:00"));
System.out.println(odt);

int year = odt.getYear();
int month = odt.getMonthValue();
int day = odt.getDayOfMonth();

But for some reason, when I select October 20th, 2023 in the dialog, November 19, 2023 is returned. I want September 20th, 2023 to be returned instead. How do I do this?

By the way, I'm using the following to get the formatted month name, if that matters:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.MONTH, month);
SimpleDateFormat monthDate = new SimpleDateFormat("MMM", Locale.getDefault()); // Use MMMM for full name of month.
String monthName = monthDate.format(cal.getTime());

Solution

  • Thanks to @OleV.V., I have the answer! I had to use the following code:

    // Set temp variables accordingly.
    LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(selection), ZoneOffset.UTC);
    
    int year = dateTime.getYear();
    int month = dateTime.getMonthValue() - 1; // Zero-based month.
    int day = dateTime.getDayOfMonth();
    
    // Text for display in inputDateEditText.
    String displayText = dateTime.format(Variables.dateTimeFormatter);
    inputDateEditText.setText(displayText);
                    
    // Set variables accordingly.
    newEventSelectedYear.set(year);
    
    newEventSelectedMonth.set(month);
    newEventSelectedDay.set(day);
    

    The key was to use LocalDateTime instead of Calendar. Variables.dateTimeFormatter can be any DateTimeFormatter, for example DateTimeFormatter.ofLcalizedDate(FormatStyle.MEDIUM) or DateTimeFormatter.ofPattern("MMM d, u"). Ole had first suggested ZoneId.systemDefault(), but that gave 1 day too early. Instead I had to set the ZoneOffset to ZoneOffset.UTC and it works great now!