Closed aarontwf closed 2 years ago
Pixel 3a emulator, seeing similar behavior in Denver when passing the current millisecond to setSelection()
:
Using v 1.1.0-rc01 - Highlights tomorrow, although the dialog is correctly drawing the black circle around today.
Using v1.2.0-alpha03 - Highlights tomorrow AND draws the black circle around tomorrow....so at least it's consistently incorrect?
I had a similar(I guess) problem with time zone. Once the date was chosen I was displaying it to the user in MM/dd/yyyy
format.
I've noticed that on devices with UTC-X timezones it was subtracting one day
I used this code to get the LocalDate
LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), clock.zone()).toLocalDate()
in my case the problem was fixed by hardcoding UTC zoneId instead of clock.zone()
any update here? I am seeing this issue on 1.2.0-alpha06
I am in timezone GMT-5 on May 6th at 9:35pm. The calendar "today" outline shows tomorrow, May 7th
@wcshi Does this also fix:
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.
Or is MaterialDatePicker.Builder.datePicker().setSelection()
supposed to be in local time?
@dsn5ft I'm using 1.2.0-beta01
and still shows displaying yesterday as today
I was able to reproduce the issue by setting the test time to December 31, 2019 09:00:00 PM UTC+13:00 (New Zealand) time zone.
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)
}
}
@ymarian any update to when this fix be rolled out
Even I am facing this problem, I am in India Timezone (GMT+5:30), and the current date is showing to be yesterdays date. @ymarian @wcshi, any idea when the change will be rolled out? Kindly try to look into this with priority as it is a production app where we are facing this issue.
I'm also facing the same issue from Nigeria. GMT+1 TimeZone.
https://github.com/material-components/material-components-android/issues/1360#issuecomment-644790081 this solution worked for me.
I'm using 1.3.0-alpha01 and still seeing yesterdays date being selected due to the timezone issue. When will the fix be availble in 1.3.0?
I used the material:1.3.0-alpha02
and it seems it resolves the issue about highlighting yesterday as current day (instead of today).
Yes Issue is fixed for highlighting yesterday as current day. but still getting issue with setSelection() method of range selection. Can you please give some solution for this?
I have the same issue of date range off by one day. Using Material library 1.2.1. Any solution?
1.3.0 is currently in beta with the fix.
1.3.0 is currently in beta with the fix.
Have you tested the fix?
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.
@VincentJoshuaET please see the following from https://github.com/material-components/material-components-android/blob/00dc4c6b5af3939418f1c7d1e4c737dc3fb7fd67/docs/components/Picker.md#timezones:
The picker interprets all long values as milliseconds from the UTC Epoch. If you have access to Java 8 libraries, it is strongly recommended you use LocalDateTime and ZonedDateTime; otherwise, you will need to use Calendar.
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());
Feb 2022, This issue is still happening in 1.5.0
Also still happens to me. Moreover, today is daylight saving time and I found the issue that we have to use the time zone of the picked date and not today.
As a workaround I implemented custom extensions:
fun <S> MaterialDatePicker<S>.addOnPositiveButtonClickListener(inliner: MaterialPickerInliner<S>, callback: (S) -> Unit): Boolean {
return addOnPositiveButtonClickListener { time ->
callback(inliner.inline(time, NegativeDirection()))
}
}
fun <S> MaterialDatePicker.Builder<S>.setSelection(inliner: MaterialPickerInliner<S>, time: S): MaterialDatePicker.Builder<S> {
setSelection(inliner.inline(time, PositiveDirection()))
return this
}
fun CalendarConstraints.Builder.setOpenAt(inliner: DateMaterialPickerInliner, time: Long): CalendarConstraints.Builder {
setOpenAt(inliner.inline(time, PositiveDirection()))
return this
}
interface MaterialPickerInliner<S> {
fun inline(s: S, inlineDirection: InlineDirection): S
}
abstract class InlineDirection(val direction:Int)
class PositiveDirection : InlineDirection(1)
class NegativeDirection : InlineDirection(-1)
class DateMaterialPickerInliner : MaterialPickerInliner<Long> {
override fun inline(s: Long, inlineDirection: InlineDirection): Long {
return inlineTimeWithTimeZone(s, inlineDirection)
}
}
class DateRangeMaterialPickerInliner : MaterialPickerInliner<androidx.core.util.Pair<Long, Long>> {
override fun inline(s: androidx.core.util.Pair<Long, Long>, inlineDirection: InlineDirection): androidx.core.util.Pair<Long, Long> {
return androidx.core.util.Pair(inlineTimeWithTimeZone(s.first, inlineDirection), inlineTimeWithTimeZone(s.second, inlineDirection))
}
}
/**
* Inlines the time to the timezone with respect to daylight saving time.
*/
private fun inlineTimeWithTimeZone(time: Long, inlineDirection: InlineDirection): Long {
val selectedTimeCalendar = Calendar.getInstance().apply { timeInMillis = time }
return time + (inlineDirection.direction * selectedTimeCalendar.timeZone.getOffset(selectedTimeCalendar.timeInMillis))
}
And the usage
val calendarConstrains = CalendarConstraints.Builder()
.setOpenAt(DateMaterialPickerInliner(), calendar.timeInMillis)
val materialDatePicker = MaterialDatePicker.create()
.setCalendarConstraints(calendarConstrains.build())
.setSelection(DateMaterialPickerInliner(), calendar.timeInMillis)
.build()
materialDatePicker.addOnPositiveButtonClickListener(DateMaterialPickerInliner()) { time ->
// TODO
}
Hey Raaj, can you take a look and see if it's still reproducible?
I could not reproduce this issue using the latest Catalog demo application
The issue is easily reproducible, I can create a demo app to show it
@danielandujar That would be very helpful and much appreciated!
Ok, so here's my demo: @raajkumars https://github.com/danielandujar/DatePickerErrorDemo
Let me add an image as explanation:
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))
After a very thorough investigation, I could not reproduce the issue which causes wrong day to be displayed as today. The other issue related to getting the current selection is a confusion that stems from the fact the datepicker uses UTC to represent the days in the picker. The selected date returned by the picker will be in UTC. To covert this value to local timezone without a timezone conversion, please use the code snippet similar to the one posted above.
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
@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();
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 )
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) }
}
val finalDate = (SpecificDate?.time ?: 0L) val timeOffset = TimeZone.getDefault().getOffset(finalDate).toLong()
val datePicker = datePicker { this.date = finalDate + if (timeOffset > 0) timeOffset else - timeOffset this.validTo = Date().time + timeOffset this.positiveButton(context.getString(R.string.common_globalokay)) { , y -> val offset = TimeZone.getDefault().getOffset(y).toLong() val selectedDate = y + if (offset > 0) offset else - offset } } datePicker.safeShow((context as AppCompatActivity))
DatePicker is a wrapper DSL over the MaterialDialog......... The offset is added and subtracted accordingly. You guys can figure out the rest.....CHILLLLLL
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)
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