Skip to content

Jetpack Compose DatePicker — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about Jetpack Compose DatePicker. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

The Problem

Your Material 3 DatePicker doesn't respond to taps, selecting a date returns the wrong value, or the dialog dismisses before selection.

Wrong Approach ❌

@Composable
fun BadDatePicker() {
    val datePickerState = rememberDatePickerState()
    // DatePicker without OK/Cancel buttons
    DatePicker(state = datePickerState)
}
// Using string instead of Long for selected date
val selectedDate = datePickerState.selectedDateMillis?.toString() // BUG: milliseconds as string

Output: Missing confirm/cancel buttons. Date string shows milliseconds.

Right Approach ✅

@Composable
fun GoodDatePicker() {
    var showDialog by remember { mutableStateOf(false) }
    var selectedDateText by remember { mutableStateOf("") }

    OutlinedButton(onClick = { showDialog = true }) {
        Text(if (selectedDateText.isEmpty()) "Pick a date" else selectedDateText)
    }

    if (showDialog) {
        val datePickerState = rememberDatePickerState(
            initialSelectedDateMillis = System.currentTimeMillis(),
            selectableDates = object : SelectableDates {
                override fun isSelectableDate(utcTimeMillis: Long): Boolean {
                    return utcTimeMillis <= System.currentTimeMillis() // Past dates only
                }
            }
        )

        DatePickerDialog(
            onDismissRequest = { showDialog = false },
            confirmButton = {
                TextButton(onClick = {
                    datePickerState.selectedDateMillis?.let { millis ->
                        val formatter = SimpleDateFormat("MM/dd/yyyy", Locale.getDefault())
                        selectedDateText = formatter.format(Date(millis))
                    }
                    showDialog = false
                }) { Text("OK") }
            },
            dismissButton = {
                TextButton(onClick = { showDialog = false }) { Text("Cancel") }
            }
        ) {
            DatePicker(state = datePickerState)
        }
    }
}

// Date range picker
val rangePickerState = rememberDateRangePickerState()
DatePickerDialog(onDismissRequest = {}, confirmButton = {}, dismissButton = {}) {
    DateRangePicker(state = rangePickerState)
}

Output: Working date picker dialog with proper date formatting.

Prevention

  • Always wrap DatePicker in DatePickerDialog for OK/Cancel buttons.
  • Use SimpleDateFormat or java.time formatting for user display.
  • Use SelectableDates to restrict selectable dates.
  • Convert selectedDateMillis from UTC millis to readable format.

Common Mistakes with compose date picker

  1. Mixing let bindings with <- bindings in do notation, producing type errors
  2. Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
  3. Non-exhaustive pattern matches that compile with warnings then crash at runtime

These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What is the difference between DatePicker and DateRangePicker?

DatePicker selects a single date. DateRangePicker selects a start and end date. Both use rememberDatePickerState and rememberDateRangePickerState respectively.

### How do I format the selected date for different locales?

Use java.time.format.DateTimeFormatter with Locale.getDefault(). For older API levels, use SimpleDateFormat with the appropriate pattern.

### Can I customize the DatePicker appearance?

Use DatePickerDefaults for colors and styling. The component follows Material 3 theming. For extensive customization, build a custom date picker using LazyVerticalGrid.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro