12

I'm calling a MaterialDatePicker like this in Android:

MaterialDatePicker.Builder<Pair<Long, Long>> builder = MaterialDatePicker.Builder.dateRangePicker();

CalendarConstraints.Builder constraintsBuilder = new CalendarConstraints.Builder();
builder.setCalendarConstraints(constraintsBuilder.build());

int dialogTheme = resolveOrThrow(getContext(), R.attr.materialCalendarTheme);
builder.setTheme(dialogTheme);

MaterialDatePicker<?> picker = builder.build();

picker.show(getFragmentManager(), picker.toString());

the library is:

dependencies {
    implementation 'com.google.android.material:material:1.2.0-alpha01'
}

How can I get the selected date of this calendar? I can't find any listener like onDateSet or OnDateSetListener

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Erjon
  • 923
  • 2
  • 7
  • 32

8 Answers8

30

Just use the addOnPositiveButtonClickListener listener called when the user confirms a valid selection:

For a single date picker:

picker.addOnPositiveButtonClickListener(new MaterialPickerOnPositiveButtonClickListener<Long>() {
      @Override public void onPositiveButtonClick(Long selection) {
        // Do something...
        //Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        //calendar.setTimeInMillis(selection);   

      }
    });

For a range date picker:

MaterialDatePicker<Pair<Long, Long>> pickerRange = builderRange.build();
pickerRange.show(....);

pickerRange.addOnPositiveButtonClickListener(new MaterialPickerOnPositiveButtonClickListener<Pair<Long, Long>>() {
  @Override public void onPositiveButtonClick(Pair<Long,Long> selection) {
       Long startDate = selection.first;
       Long endDate = selection.second;
       //Do something...
  }
});
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • 2
    Would you please enhance your answer with how to convert from Long to Calendar or LocalDate? I've tried LocalDate.ofEpochDay and LocalDateTime.ofEpochSecond but it doesn't work.Thanks – Lorenzo Petroli Jan 11 '20 at 10:39
  • 1
    @LorenzoPetroli The picker interprets all long values as milliseconds from the UTC Epoch. You can use `Instant.ofEpochMilli(dateSelected)` and `LocalDateTime.ofInstant(...)` otherwise `Calendar.setTimeInMillis(dateSelected)`. Attention to `LocalDateTime.ofEpochSecond`; it works with seconds and not milliseconds. – Gabriele Mariotti Jan 11 '20 at 10:59
  • for the conversion: fun localDateFromTimestamp(timestamp: Long): LocalDate = Instant.ofEpochMilli(timestamp) .atZone(ZoneId.systemDefault()) .toLocalDate() – Waheed Nazir Dec 31 '22 at 07:56
7

For those that struggle with this and the fact that their timestamp is off a day, here is my working solution. I have a requirement of API 23 so I could not use any of the nice Epoch functions in java.time.*. The key for me was realizing I need to do the timezone offset math.

        picker.addOnPositiveButtonClickListener(new MaterialPickerOnPositiveButtonClickListener<Long>() {
        @Override
        public void onPositiveButtonClick(Long selectedDate) {
            // user has selected a date
            // format the date and set the text of the input box to be the selected date
            // right now this format is hard-coded, this will change
            ;
            // Get the offset from our timezone and UTC.
            TimeZone timeZoneUTC = TimeZone.getDefault();
            // It will be negative, so that's the -1
            int offsetFromUTC = timeZoneUTC.getOffset(new Date().getTime()) * -1;

            // Create a date format, then a date object with our offset
            SimpleDateFormat simpleFormat = new SimpleDateFormat("MM/dd/yyyy", Locale.US);
            Date date = new Date(selectedDate + offsetFromUTC);

            dataEntry.setText(simpleFormat.format(lDate));
        }
    });
    picker.show(myActivity.getSupportFragmentManager(), picker.toString());
Brian S
  • 3,096
  • 37
  • 55
  • 1
    First time it worked, but then `offsetFromUTC` was 0. So, I set `simpleFormat.setTimeZone(TimeZone.getTimeZone("UTC"));`. Will test farther. – CoolMind May 12 '20 at 19:38
5

The answer of GR Envoy is good, but I want to change a bit. It would be better to set time zone to UTC.

private val outputDateFormat = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()).apply {
    timeZone = TimeZone.getTimeZone("UTC")
}

...
picker.addOnPositiveButtonClickListener {
    val text = outputDateFormat.format(it)
}
CoolMind
  • 26,736
  • 15
  • 188
  • 224
3

Code for Date Picker: (Here I have open date picker on click event of Button)

  datePicker.setOnClickListener(v -> {

        MaterialDatePicker datePicker =
                MaterialDatePicker.Builder.datePicker()
                        .setTitleText("Select date")
                        .build();
        datePicker.show(getSupportFragmentManager(), "date");

        datePicker.addOnPositiveButtonClickListener((MaterialPickerOnPositiveButtonClickListener<Long>) selection -> {
            String dateString = DateFormat.format("dd/MM/yyyy", new Date(selection)).toString();
            Toast.makeText(this, dateString, Toast.LENGTH_SHORT).show();
        });
    });

Code for Date Range Picker: (Here I have open date range picker on click event of Button)

dateRangePicker.setOnClickListener(v -> {
        MaterialDatePicker datePicker =
                MaterialDatePicker.Builder.dateRangePicker()
                        .setSelection(new Pair(MaterialDatePicker.thisMonthInUtcMilliseconds(),
                                MaterialDatePicker.todayInUtcMilliseconds()))
                        .setTitleText("Select dates")
                        .build();
        datePicker.show(getSupportFragmentManager(), "date");

        datePicker.addOnPositiveButtonClickListener((MaterialPickerOnPositiveButtonClickListener<Pair<Long, Long>>) selection -> {
            Long startDate = selection.first;
            Long endDate = selection.second;
            String startDateString = DateFormat.format("dd/MM/yyyy", new Date(startDate)).toString();
            String endDateString = DateFormat.format("dd/MM/yyyy", new Date(endDate)).toString();
            String date = "Start: " + startDateString + " End: " + endDateString;
            Toast.makeText(TextViewActivity.this, date, Toast.LENGTH_SHORT).show();
        });
    });

Code for Time Picker: (Here I have open time picker on click event of Button)

  timePicker.setOnClickListener(v -> {
        MaterialTimePicker timePicker = new MaterialTimePicker.Builder()
                .setTimeFormat(TimeFormat.CLOCK_12H)
                .setHour(12)
                .setTitleText("Select Appointment time")
                .setMinute(10)
                .build();
        timePicker.show(getSupportFragmentManager(), "time");

        timePicker.addOnPositiveButtonClickListener(v12 -> {
            int hour = timePicker.getHour();
            int min = timePicker.getMinute();
            Toast.makeText(TextViewActivity.this, "Time is: " + hour + ":" + min, Toast.LENGTH_SHORT).show();
        });

        timePicker.addOnNegativeButtonClickListener(v13 -> Toast.makeText(TextViewActivity.this, "Cancel", Toast.LENGTH_SHORT).show());
    });
Khyati Vara
  • 1,042
  • 13
  • 22
2

I searched around and found out many Material DatePicker Range get selected dates solutions were deprecated.

I am using dateRangePicker in my project, so below codes are solely for dateRangePicker() because I need to obtain both start date and end date.

In my Java activity code:

            materialDatePicker.addOnPositiveButtonClickListener(new MaterialPickerOnPositiveButtonClickListener() {
            @Override
            public void onPositiveButtonClick(Object selection) {
//                Get the selected DATE RANGE
                Pair selectedDates = (Pair) materialDatePicker.getSelection();
//              then obtain the startDate & endDate from the range
                final Pair<Date, Date> rangeDate = new Pair<>(new Date((Long) selectedDates.first), new Date((Long) selectedDates.second));
//              assigned variables
                Date startDate = rangeDate.first;
                Date endDate = rangeDate.second;
//              Format the dates in ur desired display mode
                SimpleDateFormat simpleFormat = new SimpleDateFormat("dd MMM yyyy");
//              Display it by setText
                datedisplay.setText("SELECTED DATE : " +  simpleFormat.format(startDate) + " Second : " + simpleFormat.format(endDate));
            }

        });

Sample output :

material datepicker android Datepicker Output

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
Vix Coder
  • 23
  • 2
1

Here's tested Kotlin version:


For single date

val datePicker: MaterialDatePicker<Long> = MaterialDatePicker
    .Builder
    .datePicker()
    .setInputMode(MaterialDatePicker.INPUT_MODE_CALENDAR)
    .setTitleText("Pick a date")
    .build()
datePicker.isCancelable = false
datePicker.show(this.supportFragmentManager, "DATE_PICKER")
datePicker.addOnPositiveButtonClickListener { long ->
   //Convert timestamp to local date
   val localDate =localDateFromTimestamp(long)
}

for date range

val dateRange: MaterialDatePicker<Pair<Long, Long>> = MaterialDatePicker
    .Builder
    .dateRangePicker()
    .setTitleText("Select date range")
    .build()
dateRange.show(this.supportFragmentManager, "DATE_RANGE_PICKER")
dateRange.addOnPositiveButtonClickListener { dates ->
    //Convert timestamp to local date and store in pair
    val datesPair = Pair(
            localDateFromTimestamp(dates.first),
            localDateFromTimestamp(dates.second)
        )
    // You can get dates like this
    // datesPair.first , datesPair.second
}

Timestamp to local date conversion

fun localDateFromTimestamp(timestamp: Long): LocalDate = Instant.ofEpochMilli(timestamp)
.atZone(ZoneId.systemDefault())
.toLocalDate()
Waheed Nazir
  • 584
  • 7
  • 11
0

enter image description here

buttonPickDate.setOnClickListener {
    
    // Create the date picker builder and set the title
    val builder = MaterialDatePicker.Builder.datePicker()
        .also {
            title = "Pick Date"
        }


    // create the date picker 
    val datePicker = builder.build()
    
    // set listener when date is selected
    datePicker.addOnPositiveButtonClickListener {
        
        // Create calendar object and set the date to be that returned from selection
        val calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
        calendar.time = Date(it)
        textView.text = "${calendar.get(Calendar.DAY_OF_MONTH)}- " +
                "${calendar.get(Calendar.MONTH) + 1}-${calendar.get(Calendar.YEAR)}"

    }

    datePicker.show(supportFragmentManager, "MyTAG")

}

enter image description here

https://ngengesenior.medium.com/pick-dates-using-the-new-material-date-picker-android-c13620bafbcb

Bolt UIX
  • 5,988
  • 6
  • 31
  • 58
0

For those of you who is looking for a Kotlin equivalent of Gabriele Mariotti's accepted answer, https://stackoverflow.com/a/58931200/3697107

Note that you need to cast "it" which is of type Any! to androidx.core.util.Pair

import androidx.core.util.Pair

val materialDatePicker = MaterialDatePicker.Builder
        .dateRangePicker()
        .build()

materialDatePicker.addOnPositiveButtonClickListener{
        val selection = it as Pair<Long, Long>
        val startDate = selection.first
        val endDate = selection.second
    }
Andrew Lee
  • 446
  • 4
  • 7