I previously wrote a post entitled Timezones in software. There are many intricacies to consider when working with time zones in software, and that post covered some that I had encountered.

I wanted to update the date inputs within the Training Plan Android app to use the MaterialDatePicker component from the material design library. It was fairly simple to implement but unfortunately it did not provide the flexibility that I required and its API is a little confusing to use. It also presented some more time zone related intricacies !

When playing with an input for editing a previously set date within the Training Plan app I noticed I strange issue. The date text I was displaying in the input was different to the day selected when the MaterialDatePicker was displayed (having had its value set using the setSelection method).

Some investigating made it apparent that MaterialDatePicker works solely based on UTC timestamps and gives no consideration to time zones. As mentioned in the previous post, we store the start date of a users training plan as the timestamp at 00:00 on the selected date in their time zone. Passing that time stamp directly into setSelection will display an incorrect date dependent on the offset between the users time zone and UTC.

For example, in my case I am based in the UK.

  • It is currently BST (UTC +1)
  • The timestamp for 00:00 on 14th April BST is equivalent to 11:00pm on the 13th April UTC

This Github issue provides further details.

The resolution is to make the adjustment manually before calling setSelection.

We use this:

	fun getTimeZone(): TimeZone {
        
        return TimeZone.getTimeZone(timeZoneIdentifier)
    }
    
    
    fun getRaceDateTimestampInMsForDatePicker(): Long? {

        val timeZone = getTimeZone()

        raceDateTimestamp?.also {

            val utcOffset = timeZone.getOffset(raceDateTimestamp!! * 1000).toLong()

            return (it * 1000) + utcOffset
        }

        return null
    }

We also needed to change our handle to convert the timestamp returned on date selection to the format that we want. If we select a date from the datepicker the timestamp passed to the handler is that equivalent to 00:00 on the selected date UTC.

For a selection of April 16th, the following log call:

Log.d(
	"DatePicker Activity",
	"Date String = ${picker.headerText}::  Date epoch values::${it}:: "
)

outputs:

Date String = Apr 16, 2021::  Date epoch values::1618531200000::

Which is midnight UTC.

Clear Date Button

The other issue that I had with the MaterialDatePicker was that it does not provide an out of the box way to implement custom controls such as a 'Clear' button for date inputs where a date has previously been set but is optional.

The resolution was to fork the material-components-android library, implement this functionality myself and then rebuild the library for inclusion within my project as outlined here.

To implement this functionality I simply added a Clear button within the mtrl_picker_actions layout XML file, and then implemented code for handling clicks within MaterialDatePicker.java.

The obvious downside of this is that you have to pull down any future changes to the library yourself. The obvious benefit however is flexibility.