16

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

marko
  • 9,029
  • 4
  • 30
  • 46
Jay
  • 238
  • 1
  • 2
  • 9

6 Answers6

15

I have a little code that I was about to delete, but the snippet is better off if it is online somewhere. It's not amazing, but it is searchable!

Objective-C code to create an array of all years since 1960. Perfect for input into a UIPicker

//Get Current Year into i2
NSDateFormatter* formatter = [[[NSDateFormatter alloc] init]autorelease];
[formatter setDateFormat:@"yyyy"];
int i2  = [[formatter stringFromDate:[NSDate date]] intValue];


//Create Years Array from 1960 to This year
years = [[NSMutableArray alloc] init];
for (int i=1960; i<=i2; i++) {
    [years addObject:[NSString stringWithFormat:@"%d",i]];
}

The UIPickerView data source and delegate methods:

- (NSInteger)numberOfComponentsInPickerView: (UIPickerView*)thePickerView {
    return 1;
}

- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component
{
    return [years count];
}
- (NSString *)pickerView:(UIPickerView *)thePickerView
titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    return [years objectAtIndex:row];
}

Don't forget the declaration in the interface

//Data
NSMutableArray *years;

The out put of it is

enter image description here

Referenced from here

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
The iOSDev
  • 5,237
  • 7
  • 41
  • 78
5

You can't do this with UIDatePicker, but you can with UIPicker.

You need to create an array for the years, and add them to the UIPicker using the UIPicker delegates

Here's a tutorial.

The iOSDev
  • 5,237
  • 7
  • 41
  • 78
James Zaghini
  • 3,895
  • 4
  • 45
  • 61
3

I cannot comment, but I was playing around with the answer by Wolvorin and I decided to do a way where the most recent year would be at the top of the Picker. Currently, his code goes oldest to most recent years.

All I changes was in my NSMutableArray setup in the viewDidLoad instead of his:

//Create Years Array from 1960 to This year
years = [[NSMutableArray alloc] init];
for (int i=1960; i<=i2; i++) {
    [years addObject:[NSString stringWithFormat:@"%d",i]];
}

I used:

years = [[NSMutableArray alloc] init];
for (int i1=i2; i1<=i2 & i1>=1920; i1--) {
    [years addObject:[NSString stringWithFormat:@"%d",i1]];
}

Which does the for in reversed order going from the most recent date, then subtracting one year (and adding it to the Array) until it gets to 1920.

My formula:

int i1=i2; i1<=i2 & i1>=1920; i1--
cowbear16
  • 55
  • 7
3

Just updating the existing answer in this post with Swift 3:

var yearsTillNow : [String] {
    var years = [String]()
    for i in (1970..<2018).reversed() {
        years.append("\(i)")
    }
    return years
}

Just use this for your UIPickerView datasource.

Sharukh Mastan
  • 1,491
  • 18
  • 17
3

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)

mahan
  • 12,366
  • 5
  • 48
  • 83
0

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

Robin
  • 704
  • 8
  • 24
  • Any possible way to share the code to work onlyyyy for years, and to start the picker after clicking in a textfield, I already tried but didnt reach a solution – Mahmoud Zinji Aug 04 '20 at 09:54
  • 1
    This is already only years, also this link should help with getting the picker with the textfield: https://stackoverflow.com/questions/12828398/show-datepicker-on-textfield-tap – Robin Aug 05 '20 at 11:06
  • When i added the whole code and replaced this part, months still appeared. and thank you for the link – Mahmoud Zinji Aug 05 '20 at 11:25
  • Thats odd, for me the line " format.dateFormat = "yyyy" " is what makes it to just year as we can see on this website with lokale set to en_US_POSIX: https://nsdateformatter.com/ Maybe check your lokale here and see what format you want. – Robin Aug 06 '20 at 12:26