iOS14でdatePickerが特定の分刻みにならない

こんばんは、iOSエンジニアの奥江です。
少しばかり苦戦したところを共有したいと思います。

# 問題
datePickerを5分刻みの時間を設定して時間を取得してもLabelに反映される時間が5分刻みの時間になりませんでした。

# 原因
iOS14まではroundsToMinuteIntervalが無効なことが原因でした。ドキュメントをもっと読まないとダメですね、、:frowning2:
https://developer.apple.com/documentation/uikit/uidatepicker/3791478-roundstominuteinterval

# 解決方法
iOS14でも5分（ここは適当な数字を設定できます）刻みで取得できるようにしたいと思います。
今回はTextFieldをタップしたらdatePickerを表示して時間と分を取得するようにします。

viewController

```
class ViewController: UIViewController {
    
    @IBOutlet weak var textField: UITextField!
    
    let datePicker = UIDatePicker()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        createToolBar()
        prepareSetting()
    }
    
    private func createToolBar() {
        let toolBar = UIToolbar()
        let doneButton = UIBarButtonItem(title: "完了",
                                         style: .done,
                                         target: nil,
                                         action: #selector(doneButtonDidTap))
        let cancellButton = UIBarButtonItem(title: "キャンセル",
                                            style: .plain,
                                            target: nil,
                                            action: #selector(cancellButtonDidTap))
        let specer = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace,
                                     target: nil,
                                     action: nil)
        toolBar.setItems([cancellButton, specer, doneButton], animated: false)
        toolBar.sizeToFit()
        textField.inputAccessoryView = toolBar
    }

    private func prepareSetting() {
        // datePickerを5分刻みにする
        datePicker.minuteInterval = 5
        // 時間表示にする
        datePicker.datePickerMode = .time
        // スタイルをドラム式にする
        datePicker.preferredDatePickerStyle = .wheels
        // textFieldにdatePickerをセット
        textField.inputView = datePicker
        // textFieldのdelegate先をselfにする
        textField.delegate = self
    }
    
    @objc
    private func doneButtonDidTap() {
        // iOS 15.0以上の時はそのまま返す。15.0以下だと四捨五入して返す
        let date: Date = {
            if #available(iOS 15.0, *) {
                return datePicker.date
            } else {
                return datePicker.date.roundsToMinuteIntervalDate()
            }
        }()
        textField.text = date.dateToString()
        view.endEditing(true)
    }
    
    @objc
    private func cancellButtonDidTap() {
        view.endEditing(true)
    }
}

extension ViewController: UITextFieldDelegate {
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
       textField.endEditing(true)
        return true
    }
}
```


extension
```
extension Date {
    // dateをStringに変換する
    func dateToString() -> String {
        let dateFormat = DateFormatter()
        dateFormat.dateFormat = "HH:mm"
        return dateFormat.string(from: self)
    }
    
    // 時間と分を取得して分を四捨五入し新たなDateを返す
    // 5分刻みの場合の計算
    func roundsToMinuteIntervalDate() -> Date {
        let calender = Calendar(identifier: .gregorian)
        let hour = Calendar.appCalender.component(.hour, from: self)
        let minute = Calendar.appCalender.component(.minute, from: self)

        // minuteが5で割り切れない場合はそのままの分を返す
        let roundMinute: Int = {
            if minute % 5 == 0 {
                return minute
            } else {
                return (5 - minute % 5) + minute
            }
        }()
        return calender.date(from: DateComponents(hour: hour, minute: roundMinute)) ?? Date()
    }
}
```


```
extension Calendar {
    static var appCalender: Calendar = {
        var calender = Calendar(identifier: .gregorian)
        calender.timeZone = TimeZone(identifier: "Asia/Tokyo")!
        calender.locale = Locale(identifier: "ja_JP")
        return calender
    }()
}
```

こんなことあんまりしないと思いますが、参考までにどうぞ:relaxed: