MaterialDatePicker returning wrong value
Asked Answered
G

3

9

I am using MaterialDatePicker in android studio for the user to be able to choose the date of birth, after selecting the date, the returned value is a long with the timestamp of the selected date (milliseconds since 01/01/1970). The problem is that the result obtained is slightly wrong, example: If the user selects the date 10/05/1998 (1st of October 1998), the date returned is one day before this, that is, the calendar returns 10/04 / 1998 (October 4, 1998).

My code:

Calendar calendar = Calendar.getInstance();
MaterialDatePicker.Builder<Long> builder = 
MaterialDatePicker.Builder.datePicker();

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

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

picker.addOnPositiveButtonClickListener(new MaterialPickerOnPositiveButtonClickListener<Long>() {
    @Override
    public void onPositiveButtonClick(Long selection) {

        calendar.setTimeInMillis(selection);
    
         SimpleDateFormat simpleDateFormat = new 
             SimpleDateFormat("dd/MM//yyyy",Locale.getDefault());
                
          txtBirthDate.setText(simpleDateFormat.format(calendar.getTime()));

    }
});

The calendar instance, now with timeInMillis has the selected date, only a day before. How can I fix this?

Gatling answered 17/9, 2020 at 0:44 Comment(7)
How are you checking if date is wrong ? Are you using a date format for it ? if yes than add the format with questionGorgonzola
@ADM i edited the question, and yes, ia m using SimpleDateFormat. But even if a get the returned long and use it in a timestamp converter site, it returns the wrong day, so the problem is on the returned value from the calendar.Gatling
Is there a solution? I have the same problem.Oomph
I got the same situation today, I have to add 1 day to it manually.Adrenalin
@SamChen I'm facing the same issue. Do you know why is the date one day before?Wendell
@Wendell Answer added.Adrenalin
@Oomph Answer added.Adrenalin
A
7

【Working solution in 2022】

It turns out that the MaterialDatePicker uses UTC time format, which means it doesn't contain any Time Zone information, as the official states here.

That means we have to do some conversion work between UTC date-time and the zone date-time, the idea would be using the LocalDateTime api:

1. For showing correct date on picker, we need to convert zone date-time to UTC date-time:

Zone date-time (Long) -> zone LocalDateTime (object) -> UTC date-time (object)-> UTC date-time (Long).

2. For getting zone date-time from picker, we need to convert UTC date-time to zone date-time:

UTC date-time (Long) -> UTC LocalDateTime (object) -> zone date-time (object) -> zone date-time (Long)

  1. Create Helper Extension Functions:

    fun Long.toLocalDateTime() = LocalDateTime.ofInstant(Instant.ofEpochMilli(this), ZoneId.systemDefault())
    
    fun Long.toUTCLocalDateTime() = LocalDateTime.ofInstant(Instant.ofEpochMilli(this), ZoneId.ofOffset("UTC", ZoneOffset.UTC))
    
  2. Show MaterialDatePicker in Fragment:

    private fun showDatePicker() {
        val datePicker = MaterialDatePicker.Builder.datePicker().run {
            setTitleText("Select Date")
            setSelection(viewModel.dateLong.value.toLocalDateTime().atZone(ZoneId.ofOffset("UTC", ZoneOffset.UTC)).toInstant().toEpochMilli())
            //setSelection(MaterialDatePicker.todayInUtcMilliseconds()) //show today's date
            build()
        }
    
        datePicker.addOnPositiveButtonClickListener {
            val dateLong = datePicker.selection!!.toUTCLocalDateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() 
    
            viewModel.updateDateLong(dateLong)       
        }
    
         datePicker.show(childFragmentManager, "")
     }
    

Demo: https://youtu.be/9YWr3fgQ214

Adrenalin answered 19/3, 2022 at 19:45 Comment(2)
This GitHub issue also confirms this behavior. github.com/material-components/material-components-android/…Arouse
It is not working when using KotlinX DateTime despite having similar result, any idea?Mall
G
0

This is because DatePicker indexes the months from 0 override this method

override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) {
    datePickerListener.onDateSet(view,year,month+1,dayOfMonth)
}
Gerrilee answered 19/3, 2022 at 21:8 Comment(0)
A
0

The only solution that worked for me was converting the desired timestamp to LocalDateTime first, then truncating to DAYS and finally converting it to UTC like following:

val selection = ZonedDateTime.now()
    .toLocalDateTime()
    .truncatedTo(ChronoUnit.DAYS)
    .toInstant(ZoneOffset.UTC)
    .toEpochMilli()

val picker = MaterialDatePicker.Builder.datePicker()
    .setSelection(selection)
    //...
    .build()

Then you can get the picked date as follows:

picker.addOnPositiveButtonClickListener { selection ->
    val selectedDate = Instant.ofEpochMilli(selection)
        .atZone(ZoneId.systemDefault())

    //...
}
Andesite answered 9/8, 2023 at 6:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.