material-components-android: [DatePicker] Incorrect TimeZones

Description:

There seems to be some strange behavior with time zones with the new date picker I am in New Zealand so our time zone is currently UTC+13 and was testing around 9am

As shown below, it is displaying yesterday as today (I increased the valid date range to include yesterday as it is hidden if not in the range)

image

Also when setting the initially selected date via MaterialDatePicker.Builder.datePicker().setSelection(), if the millis for a specific UTC date/time is given, it is not accounting for the time zone offset and is selecting the day prior. Currently our workaround is to manually add the millisecond difference from UTC to local time.

Android API version:

Min 27, Target/compile 29

Material Library version:

1.1.0-rc01

Device:

Zebra TC51

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 17
  • Comments: 33 (9 by maintainers)

Commits related to this issue

Most upvoted comments

I am using 1.3.0-alpha01 and have the same problem.

So, this is my workaround.

val picker = MaterialDatePicker.Builder.datePicker()
            .....
            .build()
picker.show(supportFragmentManager, picker.toString())
picker.addOnPositiveButtonClickListener {
            val utcTime = Date(it)
            val format = "yyy/MM/dd HH:mm:ss"
            val sdf = SimpleDateFormat(format, Locale.getDefault())
            sdf.timeZone = TimeZone.getTimeZone("UTC")
            val gmtTime = SimpleDateFormat(format, Locale.getDefault()).parse(sdf.format(utcTime))
            gmtTime?.let {  date ->
                vm.setNextDueDate(date.time)
            }
}

Feb 2022, This issue is still happening in 1.5.0

@ymarian any update to when this fix be rolled out

@danielandujar If my memory serves right the first implementation of date picker class used local timezone. However in order to avoid a number of bug the implementation was changed later to use UTC. That said you points are valid. It will be inconvenient for developers to change the timezone of the selected date(s) everywhere in the code. Perhaps we could add the following methods to the picker:

public final S getSelectionInTimezone(@NotNull Timezone timezone);
public final S getSelectionInLocalTimezone();

Thanks for putting together a demo app. Based on this app and the information you provided, here is what I see:

Current Host Date/time: Fri, Apr 1 2022 10 PM Current Date/time in UTC: Sat, Apr 2, 2022 2:00 AM Selected Date/time in UTC: Sat, Apr 2, 2022 12:00 APM

So yes, the difference would be 2 hours ago. I think that the confusion stems from the fact that date picker receives and returns date values in UTC. Whereas the app is expecting to receive the selected date in local timezone. To convert the selected date in UTC to local date without changing the values you can try something like this:

var selectedUtc = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
selectedUtc.setTimeInMillis(millis)
var selectedLocal = Calendar.getInstance()
selectedLocal.clear()
selectedLocal.set(selectedUtc.get(Calendar.YEAR), selectedUtc.get(Calendar.MONTH), selectedUtc.get(Calendar.DATE))

@dsn5ft I’m using 1.2.0-beta01 and still shows displaying yesterday as today

Solution for me.

val d = Calendar.getInstance().apply {
   timeInMillis = viewModel.endTime.value + TimeZone.getDefault().rawOffset
}
MaterialDatePicker.Builder.datePicker()
   .setTitleText("Select date")
   .setSelection(d.timeInMillis)
   .build()
   .apply {
      addOnPositiveButtonClickListener { viewModel.setDate(it) }
   }

So @raajkumars, this is not what we would expect from the datepicker itself, having to do workarounds for something obvious as dates. The DatePicker should AT BARE MINIMUN say that in the docs and implementation samples. But ideally do Both of these: a) Be defaulted to the device’s default TimeZone b) Have the ability to change the timezone in code.

and by the way, This it is the same reason the ticket was open in the first place

1.3.0 is currently in beta with the fix.

Not working for me. I used Instant.now().toEpochMilli() in setSelection() and the previous day gets selected.

This is worked for me

public Date dateFromUTC(Date date) {
    return new Date(date.getTime() + Calendar.getInstance().getTimeZone().getOffset(new Date().getTime()));
}

// call dateFromUTC in setSelection
MaterialDatePicker.Builder<Long> builder = MaterialDatePicker.Builder.datePicker();
builder.setSelection(dateFromUTC(YOUR_DATE).getTime());

The secret for me was to set setTextInputFormat’s SimpleDateFormat’s timezone to be UTC

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

(along with https://github.com/material-components/material-components-android/issues/882#issuecomment-1111374962 )