javaandroidmaterialdatepicker

MaterialDatePicker android selects previous to specified date instead of the specified date


When I create a MaterialDatePicker it picks the previous date of the date I specified, instead of the specified date:

You can see that the EditText has May 12, 2019 but the DatePicker shows as May 11, 2019

You can see that the EditText has May 12, 2019 but the DatePicker shows as May 11, 2019

Code for the openDatePicker is:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    binding = ActivityMainBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());

    setSupportActionBar(binding.toolbar);

    String dateText = "May 12, 2019";
    binding.etDate.setText(dateText);
    try {
        Date date = new SimpleDateFormat("MMM dd, yyyy").parse(dateText);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        binding.etDate.setTag(cal);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    binding.etDate.setOnClickListener(v -> {
        Calendar defaultCal = Calendar.getInstance();
        if (binding.etDate.getTag() != null) {
            defaultCal = (Calendar) binding.etDate.getTag();
        }
        openDatePicker(binding.etDate, defaultCal, createDatePickerConstraints(defaultCal, null, null));
    });
}

private void openDatePicker(final EditText tv, Calendar defaultDate, CalendarConstraints constraints) {
    try {
        MaterialDatePicker.Builder<Long> builder = MaterialDatePicker.Builder.datePicker();
        builder.setCalendarConstraints(constraints);
        builder.setSelection(defaultDate.getTimeInMillis());
        MaterialDatePicker<Long> datePicker = builder.build();
        datePicker.addOnPositiveButtonClickListener(selection -> {
            Calendar selectedCalObj = Calendar.getInstance();
            selectedCalObj.setTimeInMillis((long) selection);
            SimpleDateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH);
            dateFormat.setTimeZone(TimeZone.getDefault());
            String date = dateFormat.format(selectedCalObj.getTime())
                    .replace("a.m.", "AM")
                    .replace("p.m.", "PM")
                    .replace("am", "AM")
                    .replace("pm", "PM");;
            tv.setText(date);
            tv.setTag(selectedCalObj);
        });
        datePicker.addOnNegativeButtonClickListener(view -> {
            Log.d(TAG, "Cancelled");
        });
        datePicker.show(getSupportFragmentManager(), TAG);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

// helper function to give the constraints:
private CalendarConstraints createDatePickerConstraints(final Calendar entry, final Calendar start, final Calendar end) {
    CalendarConstraints.Builder constraintsBuilder = new CalendarConstraints.Builder();
    if (entry != null)
        constraintsBuilder.setOpenAt(entry.getTimeInMillis());
    if (start != null) {
        constraintsBuilder.setStart(start.getTimeInMillis());
        constraintsBuilder.setValidator(DateValidatorPointForward.from(start.getTimeInMillis()));
    }
    if (end != null) {
        constraintsBuilder.setEnd(end.getTimeInMillis());
        constraintsBuilder.setValidator(DateValidatorPointBackward.before(end.getTimeInMillis()));
    }
    return constraintsBuilder.build();
}

Possible way that I know to is to fix by offsetting the EditText binding.etDate.setTag at onCreate to the current timezone I am in (since the issue is the time being May 12, 2019 0:00:00 that might be the issue of the DatePicker picking the previous date when opened) but it would be really helpful if there is a better way to do this, since this seems like a more common code that will be useful everywhere so that I can make it as a library and just call this as a library code in my main application.

Any help would be appreciated.


Solution

  • So, after going through loads of GitHub issues, I found that MaterialDatePicker has getters and setters only for time in UTC, so offsetting values won't be a good idea so pass in the current time to it as a UTC like: Link for converting current timezone to UTC

    My sample code:

    try { 
        SimpleDateFormat fromDate = new SimpleDateFromat("MMM dd, yyyy");
        fromDate.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date date = fromDate.parse(inputDateString);
        Calendar cal = Calendar.getInstance(Locale.getDefault());
        cal.setTime(date);
        binding.etDate.setTag(cal);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    

    I will be using the tag from the EditText later to populate my CalendarConstraints and the MaterialDatePicker's setSelection later.

    Hope this is helpful!