Material3のDatePicker, TimePickerの仕様について

# はじめに
 JetpackCompose個人開発でDatePickerやTimePickerを使った時に迷ったりつまづいたりした部分をまとめます。

### DatePicker, TimePickerとは
MaterialDesign3で提供されている、日時を取得するUIコンポーネントです。
[DatePicker](https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#DatePicker(androidx.compose.material3.DatePickerState,androidx.compose.ui.Modifier,androidx.compose.material3.DatePickerFormatter,kotlin.Function0,kotlin.Function0,kotlin.Boolean,androidx.compose.material3.DatePickerColors))
[TimePicker](https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#TimePicker(androidx.compose.material3.TimePickerState,androidx.compose.ui.Modifier,androidx.compose.material3.TimePickerColors,androidx.compose.material3.TimePickerLayoutType))

# DatePicker

### 実装方法
build.gradleに`implementation("androidx.compose.material3:material3:$m3-version"`
を追加して、Composable関数に`@OptIn(ExperimentalMaterial3Api::class)`などのアノテーションを使用することで組み込むことができます。

### サンプルコード
先ほどのリンク先にあるDataPickerのサンプルコードです。
```kotlin:datePicker.kt
//... import

Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
    // Pre-select a date for January 4, 2020
    val datePickerState = rememberDatePickerState(initialSelectedDateMillis = 1578096000000)
    DatePicker(state = datePickerState, modifier = Modifier.padding(16.dp))

    Text("Selected date timestamp: ${datePickerState.selectedDateMillis ?: "no selection"}")
}
```
datePickerの実装にはDatePickerState型の引数が必要であることがわかります。また、datePickerStateの変数宣言では初期値を定義されており、どのような形でデータが保持されているのかもわかります。その下のTextから、値は`datePickerState.selectedDateMillis`に保持されているということもわかりました。

### DatePickerのデーターを保存する
データを取得したら保持したいですよね。実は、導入する部分についてはまとめられていましたが、そこからどう値を保持すればいいのか分からず、kotloinの実装に慣れていない私は苦戦しました。

結論、DatePickerに引数で渡した`datePickerState`に対して変更が行われるため、引数のdataPickerStateを参照すればいいです。変更が行われたかどうかについては`DatePickerDialog`と組み合わせると簡単に管理できます。

上記のコード同様、DatePickerのドキュメントにあるサンプルコードの抜粋です。
```kotlin:DatePickerDialog.kt
// ...
    DatePickerDialog(
        // Dialogの外側を触ったときの挙動
        onDismissRequest = {
            openDialog.value = false
        },
        // OKボタン
        confirmButton = {
            TextButton(
                // OKボタンを押したときの挙動
                onClick = {
                    openDialog.value = false
                    // ...
                },
                enabled = confirmEnabled.value
            ) {
                Text("OK")
            }
        },
        // Cancelボタン
        dismissButton = {
            TextButton(
                onClick = {
                    // Cancelボタンを押したときの挙動
                    openDialog.value = false
                }
            ) {
                Text("Cancel")
            }
        }
    ) {
        DatePicker(state = datePickerState)
    }
```
`DatePickerDialog`の引数に、各ボタンを押したとき実行する処理を入れられるので、データ保持などをしたいのであればOKの時のonClickの処理でデータ保持の関数を呼び出してあげるとうまくいきそうですね。保持するデータは先ほど確認した通り、`datePickerState.selectedDateMillis`で取り出せるのでこちらを渡せばうまくいくはずです。


# TimePicker
### サンプルコード
TimePickerのサンプルコードの抜粋です。
```kotlin:TimePicker.kt
// ...
TimePickerDialog(
    onCancel = { showTimePicker = false },
    onConfirm = {
        val cal = Calendar.getInstance()
        cal.set(Calendar.HOUR_OF_DAY, state.hour)
        cal.set(Calendar.MINUTE, state.minute)
        cal.isLenient = false
        snackScope.launch {
            snackState.showSnackbar("Entered time: ${formatter.format(cal.time)}")
        }
        showTimePicker = false
    },
) {
    TimePicker(state = state)
}
```

TimePickerをDatePicker同様に実装しようとしたら、DatePickerDialogのようなUIコンポーネントが提供されていないことがわかりました。調べて[該当するサンプルコード](https://cs.android.com/androidx/platform/tools/dokka-devsite-plugin/+/master:testData/compose/samples/material3/samples/TimePickerSamples.kt;l=230;drc=03ca30d22e6ee3483142f2e4048db459cb5afb79)を見つけることができました。

このリンクから引用して実装すると、[TimePickerのドキュメント](https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#TimePicker(androidx.compose.material3.TimePickerState,androidx.compose.ui.Modifier,androidx.compose.material3.TimePickerColors,androidx.compose.material3.TimePickerLayoutType))にある画像と同様のUIコンポーネントを実装できました。

### TimePickerのデーターを保存する
DatePicker同様、TimePickerに`rememberTimePickerState()`を使用して定義した値`state: TimePickerState`を引数で渡して、変更がこの引数に対して行われます。取り出す際は`state.hour`や`state.minute`とすれば値を返してくれます。