UIDatePicker to show year only

Viewed 26273

Is there a way to have a UIDatePicker show year only?

6 Answers

It is not possible to set only Year and Month. Only these modes are available as of iOS 13.5.1

  • time: A mode that displays the date in hours, minutes, and (optionally) an AM/PM designation. The exact items shown and their order depend upon the locale set. An example of this mode is [ 6 | 53 | PM ].

  • date: A mode that displays the date in months, days of the month, and years. The exact order of these items depends on the locale setting. An example of this mode is [ November | 15 | 2007 ].

  • dateAndTime: A mode that displays the date as unified day of the week, month, and day of the month values, plus hours, minutes, and (optionally) an AM/PM designation. The exact order and format of these items depends on the locale set. An example of this mode is [ Wed Nov 15 | 6 | 53 | PM ].

  • countDownTimer: A mode that displays hour and minute values, for example [ 1 | 53 ]. The application must set a timer to fire at the proper interval and set the date picker as the seconds tick down. UIDatePicker.Mode - developer.apple.com


You may build it using a custom UIPickerView.

class DatePickerViewController: UIViewController {
    var dates =  [Date]()
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .white
        
        
        var date = Date().addYear(n: -10)
        let endDate = Date().addYear(n: 10)
        
        repeat {
            date = date.addMonth(n: 1)
            dates.append(date)
        } while date < endDate
        
        
        let picker = UIPickerView()
        picker.dataSource = self
        picker.delegate = self
        picker.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(picker)
        
        picker.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        picker.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        picker.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
        picker.heightAnchor.constraint(equalToConstant: 500).isActive = true
    }
}


extension  DatePickerViewController: UIPickerViewDataSource {
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return self.dates.count
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        let date = self.dates[row]
        return date.stringDate()
    }
    
    func view(forRow row: Int, forComponent component: Int) -> UIView? {
        let label =  UILabel()
        return label
    }
}

extension  DatePickerViewController: UIPickerViewDelegate {
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        let date = self.dates[row]
        // Date that the user select. 
        print( date, date.stringDate())
    }
}


extension Date {
    public  func addYear(n: Int) -> Date {
        let calendar = Calendar.current
        return calendar.date(byAdding: .year, value: n, to: self)!
    }
    
    public  func addMonth(n: Int) -> Date {
        let calendar = Calendar.current
        return calendar.date(byAdding: .month, value: n, to: self)!
    }
    
    public  func stringDate() -> String {
        let calendar  = Calendar.current
        let dateFormatter = DateFormatter()
        
        dateFormatter.timeZone = calendar.timeZone
        dateFormatter.locale = calendar.locale
        // Use YYYY to show year only. 
        // Use MMMM to show month only. 
        dateFormatter.setLocalizedDateFormatFromTemplate("MMMM YYYY")
        
        let dateString = dateFormatter.string(from: self)
        return dateString
    }
}

Just change the following two lines- add/subtract as many years you wish to show.

var date = Date().addYear(n: -10) 
let endDate = Date().addYear(n: 10)

I changed Sharukh Mastan's code slightly to always show the current year on top.

var formattedDate: String? = ""

let format = DateFormatter()
format.dateFormat = "yyyy"
formattedDate = format.string(from: date)

var yearsTillNow: [String] {
    var years = [String]()
    for i in (Int(formattedDate!)!-70..<Int(formattedDate!)!+1).reversed() {
        years.append("\(i)")
    }
    return years
}

print(yearsTillNow)

This prints an array of years going back for 70 years which you can use as UIPickerView datasource

Related