Working With Date Picker in Jetpack Compose

Andrew Phiri
5 min readFeb 14, 2024

--

Date Pickers give the user the option to pick a date or enter one manually. If you need to let users pick a date in your app, this article will show you how to use date pickers in Jetpack Compose.

Date Pickers

We can easily create a Date Picker by simply providing it with the required parameter state. This holds the state of the date picker that will be remembered across recompositions.

Let’s create a date picker as shown below.

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyDatePicker() {
val dateState = rememberDatePickerState()
DatePicker(
state = dateState
)
}
Date Picker

Then we can use the state to get the date selected. The date selected is stored in millis. So we need to convert the millis to a date object.

This is the code we will use to manipulate the date selected.

import android.os.Build
import androidx.annotation.RequiresApi
import java.time.Instant
import java.time.LocalDate
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Locale
class DateUtils { @RequiresApi(Build.VERSION_CODES.O)
fun convertMillisToLocalDate(millis: Long) : LocalDate {
return Instant
.ofEpochMilli(millis)
.atZone(ZoneId.systemDefault())
.toLocalDate()
}
@RequiresApi(Build.VERSION_CODES.O)
fun convertMillisToLocalDateWithFormatter(date: LocalDate, dateTimeFormatter: DateTimeFormatter) : LocalDate {
//Convert the date to a long in millis using a dateformmater
val dateInMillis = LocalDate.parse(date.format(dateTimeFormatter), dateTimeFormatter)
.atStartOfDay(ZoneId.systemDefault())
.toInstant()
.toEpochMilli()

//Convert the millis to a localDate object
return Instant
.ofEpochMilli(dateInMillis)
.atZone(ZoneId.systemDefault())
.toLocalDate()
}
@RequiresApi(Build.VERSION_CODES.O)
fun dateToString(date: LocalDate): String {
val dateFormatter = DateTimeFormatter.ofPattern("EEEE, dd MMMM, yyyy", Locale.getDefault())
val dateInMillis = convertMillisToLocalDateWithFormatter(date, dateFormatter)
return dateFormatter.format(dateInMillis)
}
}

To show you how let us create a text composable below the dialog, and then we will pick a date, which will then be converted to a string.

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ManufacturedDate() {
val dateState = rememberDatePickerState()
val millisToLocalDate = dateState.selectedDateMillis?.let {
DateUtils().convertMillisToLocalDate(it)
}
val dateToString = millisToLocalDate?.let {
DateUtils().dateToString(millisToLocalDate)
} ?: ""
Column {
DatePicker(
state = dateState
)
Text(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
text = dateToString
)
}
}
Date selected

When we select a date, the date selected is shown as indicated above.

If we want to manually input the date, we simply change showModeToggle to true and we can input our date by simply clicking on the edit icon or pen/pencil like icon shown. We can also change the title and headline of the picker as shown below. Remember thour that when you provide a headline on the picker, the date selected will not be shown on the headline label. Unless the headline you provide is the date selected.

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ManufacturedDate() {
val dateState = rememberDatePickerState()
val millisToLocalDate = dateState.selectedDateMillis?.let {
DateUtils().convertMillisToLocalDate(it)
}
val dateToString = millisToLocalDate?.let {
DateUtils().dateToString(millisToLocalDate)
} ?: ""
Column {
DatePicker(
title = {
Text(text = "Manufactured Date")
},
headline = { Text(text = "Car's manufactured date")},
state = dateState,
showModeToggle = true
)
Text(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
text = dateToString
)
}
}
Title, HeadLine, showModeToggle

We can also change the format of the date. If we want the code for a day of the week, we simply provide the pattern to the dateFormatter parameter. So when a user selects a date, the date with a date will be shown on the headline label.

@RequiresApi(Build.VERSION_CODES.O)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ManufacturedDate() {
val dateState = rememberDatePickerState()
val millisToLocalDate = dateState.selectedDateMillis?.let {
DateUtils().convertMillisToLocalDate(it)
}
val dateToString = millisToLocalDate?.let {
DateUtils().dateToString(millisToLocalDate)
} ?: ""
Column {
DatePicker(
dateFormatter = DatePickerFormatter(
selectedDateSkeleton = "EE, dd MMM, yyyy",
),
title = {
Text(text = "Manufactured Date")
},
state = dateState,
showModeToggle = true
)
Text(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
text = dateToString
)
}
}
Date with day

DatePicker with DatePickerDialog

The recommended way to use a date picker is to embed it in a DatePickerDialog. That gives us more control over it. We can easily show it and dismiss it.

I will create a text composable and make it clickable. Whenever a user clicks on it, the DatePickerDialog with the DatePicker will show up. The user can easily dismiss it by clicking cancel or touching outside the dialog. Here is the code.

@RequiresApi(Build.VERSION_CODES.O)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DatePickerWithDialog(
modifier: Modifier = Modifier
) {
val dateState = rememberDatePickerState()
val millisToLocalDate = dateState.selectedDateMillis?.let {
DateUtils().convertMillisToLocalDate(it)
}
val dateToString = millisToLocalDate?.let {
DateUtils().dateToString(millisToLocalDate)
} ?: "Choose Date"
    var showDialog by remember { mutableStateOf(false) }
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = {
showDialog = true
}),
text = dateToString,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.headlineMedium
)
if (showDialog) {
DatePickerDialog(
onDismissRequest = { showDialog = false },
confirmButton = {
Button(
onClick = { showDialog = false }
) {
Text(text = "OK")
}
},
dismissButton = {
Button(
onClick = { showDialog = false }
) {
Text(text = "Cancel")
}
}
) {
DatePicker(
state = dateState,
showModeToggle = true
)
}
}
}
}

When we click on the text composable “Choose Date,” this is what we get.

Date Picked embedded in a dialog

When we press “OK,” this is what we get.

Date selected

As easy as that.

You can find the code here on github.

And don’t forget to follow me on X.

--

--

Andrew Phiri

Native Android Developer | Kotlin. Sharing Android tips and tricks