I need a UIDatePicker
for selecting Month and Year only. I checked the class reference documents. Looks like UIDatePicker
is a UIView
. I imagined UIPickerView
may be a sub view and I can hide the component if I can grab it. But no. That was not possible. Do I have to create my own custom picker then? Any ideas?
-
Since this question was asked, open source libraries such as SRMonthPicker, which I recommend, have been added to CocoaPods. – Peter DeWeese Aug 25 '15 at 16:05
12 Answers
Here is a solution to get the same effect. For using this snippet of code you should replace UIPickerView
to CDatePickerViewEx
in nib file in "Custom class" of "Indentity inspector".
.h file
#import <UIKit/UIKit.h>
@interface CDatePickerViewEx : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource>
@property (nonatomic, strong, readonly) NSDate *date;
-(void)selectToday;
@end
.m file
#import "CDatePickerViewEx.h"
// Identifiers of components
#define MONTH ( 0 )
#define YEAR ( 1 )
// Identifies for component views
#define LABEL_TAG 43
@interface CDatePickerViewEx()
@property (nonatomic, strong) NSIndexPath *todayIndexPath;
@property (nonatomic, strong) NSArray *months;
@property (nonatomic, strong) NSArray *years;
-(NSArray *)nameOfYears;
-(NSArray *)nameOfMonths;
-(CGFloat)componentWidth;
-(UILabel *)labelForComponent:(NSInteger)component selected:(BOOL)selected;
-(NSString *)titleForRow:(NSInteger)row forComponent:(NSInteger)component;
-(NSIndexPath *)todayPath;
-(NSInteger)bigRowMonthCount;
-(NSInteger)bigRowYearCount;
-(NSString *)currentMonthName;
-(NSString *)currentYearName;
@end
@implementation CDatePickerViewEx
const NSInteger bigRowCount = 1000;
const NSInteger minYear = 2008;
const NSInteger maxYear = 2030;
const CGFloat rowHeight = 44.f;
const NSInteger numberOfComponents = 2;
@synthesize todayIndexPath;
@synthesize months;
@synthesize years = _years;
-(void)awakeFromNib
{
[super awakeFromNib];
self.months = [self nameOfMonths];
self.years = [self nameOfYears];
self.todayIndexPath = [self todayPath];
self.delegate = self;
self.dataSource = self;
[self selectToday];
}
-(NSDate *)date
{
NSInteger monthCount = [self.months count];
NSString *month = [self.months objectAtIndex:([self selectedRowInComponent:MONTH] % monthCount)];
NSInteger yearCount = [self.years count];
NSString *year = [self.years objectAtIndex:([self selectedRowInComponent:YEAR] % yearCount)];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"MMMM:yyyy"];
NSDate *date = [formatter dateFromString:[NSString stringWithFormat:@"%@:%@", month, year]];
return date;
}
#pragma mark - UIPickerViewDelegate
-(CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
{
return [self componentWidth];
}
-(UIView *)pickerView: (UIPickerView *)pickerView
viewForRow: (NSInteger)row
forComponent: (NSInteger)component
reusingView: (UIView *)view
{
BOOL selected = NO;
if(component == MONTH)
{
NSInteger monthCount = [self.months count];
NSString *monthName = [self.months objectAtIndex:(row % monthCount)];
NSString *currentMonthName = [self currentMonthName];
if([monthName isEqualToString:currentMonthName] == YES)
{
selected = YES;
}
}
else
{
NSInteger yearCount = [self.years count];
NSString *yearName = [self.years objectAtIndex:(row % yearCount)];
NSString *currenrYearName = [self currentYearName];
if([yearName isEqualToString:currenrYearName] == YES)
{
selected = YES;
}
}
UILabel *returnView = nil;
if(view.tag == LABEL_TAG)
{
returnView = (UILabel *)view;
}
else
{
returnView = [self labelForComponent: component selected: selected];
}
returnView.textColor = selected ? [UIColor blueColor] : [UIColor blackColor];
returnView.text = [self titleForRow:row forComponent:component];
return returnView;
}
-(CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
return rowHeight;
}
#pragma mark - UIPickerViewDataSource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return numberOfComponents;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
if(component == MONTH)
{
return [self bigRowMonthCount];
}
return [self bigRowYearCount];
}
#pragma mark - Util
-(NSInteger)bigRowMonthCount
{
return [self.months count] * bigRowCount;
}
-(NSInteger)bigRowYearCount
{
return [self.years count] * bigRowCount;
}
-(CGFloat)componentWidth
{
return self.bounds.size.width / numberOfComponents;
}
-(NSString *)titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if(component == MONTH)
{
NSInteger monthCount = [self.months count];
return [self.months objectAtIndex:(row % monthCount)];
}
NSInteger yearCount = [self.years count];
return [self.years objectAtIndex:(row % yearCount)];
}
-(UILabel *)labelForComponent:(NSInteger)component selected:(BOOL)selected
{
CGRect frame = CGRectMake(0.f, 0.f, [self componentWidth],rowHeight);
UILabel *label = [[UILabel alloc] initWithFrame:frame];
label.textAlignment = UITextAlignmentCenter;
label.backgroundColor = [UIColor clearColor];
label.textColor = selected ? [UIColor blueColor] : [UIColor blackColor];
label.font = [UIFont boldSystemFontOfSize:18.f];
label.userInteractionEnabled = NO;
label.tag = LABEL_TAG;
return label;
}
-(NSArray *)nameOfMonths
{
NSDateFormatter *dateFormatter = [NSDateFormatter new];
return [dateFormatter standaloneMonthSymbols];
}
-(NSArray *)nameOfYears
{
NSMutableArray *years = [NSMutableArray array];
for(NSInteger year = minYear; year <= maxYear; year++)
{
NSString *yearStr = [NSString stringWithFormat:@"%i", year];
[years addObject:yearStr];
}
return years;
}
-(void)selectToday
{
[self selectRow: self.todayIndexPath.row
inComponent: MONTH
animated: NO];
[self selectRow: self.todayIndexPath.section
inComponent: YEAR
animated: NO];
}
-(NSIndexPath *)todayPath // row - month ; section - year
{
CGFloat row = 0.f;
CGFloat section = 0.f;
NSString *month = [self currentMonthName];
NSString *year = [self currentYearName];
//set table on the middle
for(NSString *cellMonth in self.months)
{
if([cellMonth isEqualToString:month])
{
row = [self.months indexOfObject:cellMonth];
row = row + [self bigRowMonthCount] / 2;
break;
}
}
for(NSString *cellYear in self.years)
{
if([cellYear isEqualToString:year])
{
section = [self.years indexOfObject:cellYear];
section = section + [self bigRowYearCount] / 2;
break;
}
}
return [NSIndexPath indexPathForRow:row inSection:section];
}
-(NSString *)currentMonthName
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"MMMM"];
return [formatter stringFromDate:[NSDate date]];
}
-(NSString *)currentYearName
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy"];
return [formatter stringFromDate:[NSDate date]];
}
@end

- 3,976
- 9
- 30
- 39

- 4,235
- 3
- 34
- 32
-
-
2Here is a link to githab project: https://github.com/IgorFedorchuk/MonthYearDatePicker – Igor Mar 18 '13 at 07:07
-
Could you tell me the purpose of using such constants as bigRowMonthCount and bigRowYearCount? – Konstantin Jun 10 '15 at 13:00
Yeah, you probably want to just make your own picker. You don't have to subclass it or anything, though; just use a generic UIPickerView
and return appropriate values from your UIPickerViewDelegate
/UIPickerViewDataSource
methods.

- 57,021
- 16
- 130
- 131
-
5How do you deal with the fact that you have to prevent the picker from selecting future dates? – CodeBlue Jan 22 '13 at 23:05
I rewrote Igor's answer in Swift:
class CLIVEDatePickerView: UIPickerView {
enum Component: Int {
case Month = 0
case Year = 1
}
let LABEL_TAG = 43
let bigRowCount = 1000
let numberOfComponentsRequired = 2
let months = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"]
var years: [String] {
get {
var years: [String] = [String]()
for i in minYear...maxYear {
years.append("\(i)")
}
return years;
}
}
var bigRowMonthsCount: Int {
get {
return bigRowCount * months.count
}
}
var bigRowYearsCount: Int {
get {
return bigRowCount * years.count
}
}
var monthSelectedTextColor: UIColor?
var monthTextColor: UIColor?
var yearSelectedTextColor: UIColor?
var yearTextColor: UIColor?
var monthSelectedFont: UIFont?
var monthFont: UIFont?
var yearSelectedFont: UIFont?
var yearFont: UIFont?
let rowHeight: NSInteger = 44
/**
Will be returned in user's current TimeZone settings
**/
var date: NSDate {
get {
let month = self.months[selectedRowInComponent(Component.Month.rawValue) % months.count]
let year = self.years[selectedRowInComponent(Component.Year.rawValue) % years.count]
let formatter = NSDateFormatter()
formatter.dateFormat = "MM yyyy"
return formatter.dateFromString("\(month) \(year)")!
}
}
var minYear: Int!
var maxYear: Int!
override init(frame: CGRect) {
super.init(frame: frame)
loadDefaultParameters()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadDefaultParameters()
}
override func awakeFromNib() {
super.awakeFromNib()
loadDefaultParameters()
}
func loadDefaultParameters() {
minYear = NSCalendar.currentCalendar().components(NSCalendarUnit.Year, fromDate: NSDate()).year
maxYear = minYear! + 10
self.delegate = self
self.dataSource = self
monthSelectedTextColor = UIColor.blueColor()
monthTextColor = UIColor.blackColor()
yearSelectedTextColor = UIColor.blueColor()
yearTextColor = UIColor.blackColor()
monthSelectedFont = UIFont.boldSystemFontOfSize(17)
monthFont = UIFont.boldSystemFontOfSize(17)
yearSelectedFont = UIFont.boldSystemFontOfSize(17)
yearFont = UIFont.boldSystemFontOfSize(17)
}
func setup(minYear: NSInteger, andMaxYear maxYear: NSInteger) {
self.minYear = minYear
if maxYear > minYear {
self.maxYear = maxYear
} else {
self.maxYear = minYear + 10
}
}
func selectToday() {
selectRow(todayIndexPath.row, inComponent: Component.Month.rawValue, animated: false)
selectRow(todayIndexPath.section, inComponent: Component.Year.rawValue, animated: false)
}
var todayIndexPath: NSIndexPath {
get {
var row = 0.0
var section = 0.0
for cellMonth in months {
if cellMonth == currentMonthName {
row = Double(months.indexOf(cellMonth)!)
row = row + Double(bigRowMonthsCount / 2)
break
}
}
for cellYear in years {
if cellYear == currentYearName {
section = Double(years.indexOf(cellYear)!)
section = section + Double(bigRowYearsCount / 2)
break
}
}
return NSIndexPath(forRow: Int(row), inSection: Int(section))
}
}
var currentMonthName: String {
get {
let formatter = NSDateFormatter()
let locale = NSLocale(localeIdentifier: "en_US")
formatter.locale = locale
formatter.dateFormat = "MM"
return formatter.stringFromDate(NSDate())
}
}
var currentYearName: String {
get {
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy"
return formatter.stringFromDate(NSDate())
}
}
func selectedColorForComponent(component: NSInteger) -> UIColor {
if component == Component.Month.rawValue {
return monthSelectedTextColor!
}
return yearSelectedTextColor!
}
func colorForComponent(component: NSInteger) -> UIColor {
if component == Component.Month.rawValue {
return monthTextColor!
}
return yearTextColor!
}
func selectedFontForComponent(component: NSInteger) -> UIFont {
if component == Component.Month.rawValue {
return monthSelectedFont!
}
return yearSelectedFont!
}
func fontForComponent(component: NSInteger) -> UIFont {
if component == Component.Month.rawValue {
return monthFont!
}
return yearFont!
}
func titleForRow(row: Int, forComponent component: Int) -> String? {
if component == Component.Month.rawValue {
return self.months[row % self.months.count]
}
return self.years[row % self.years.count]
}
func labelForComponent(component: NSInteger) -> UILabel {
let frame = CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height: CGFloat(rowHeight))
let label = UILabel(frame: frame)
label.textAlignment = NSTextAlignment.Center
label.backgroundColor = UIColor.clearColor()
label.userInteractionEnabled = false
label.tag = LABEL_TAG
return label
}
}
extension CLIVEDatePickerView: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return numberOfComponentsRequired
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if(component == Component.Month.rawValue) {
return bigRowMonthsCount
} else {
return bigRowYearsCount
}
}
func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
return self.bounds.size.width / CGFloat(numberOfComponentsRequired)
}
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
var selected = false
if component == Component.Month.rawValue {
let monthName = self.months[(row % self.months.count)]
if monthName == currentMonthName {
selected = true
}
} else {
let yearName = self.years[(row % self.years.count)]
if yearName == currentYearName {
selected = true
}
}
var returnView: UILabel
if view?.tag == LABEL_TAG {
returnView = view as! UILabel
} else {
returnView = labelForComponent(component)
}
returnView.font = selected ? selectedFontForComponent(component) : fontForComponent(component)
returnView.textColor = selected ? selectedColorForComponent(component) : colorForComponent(component)
returnView.text = titleForRow(row, forComponent: component)
return returnView
}
func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return CGFloat(rowHeight)
}
}

- 434
- 8
- 10
No, this cannot be done using the stock UIDatePicker
.
UIDatePickerModeDate
The date picker displays 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 ].
Source: UIDatePicker class reference
I recommend customizing a UIPickerView
to use two components and populating its rows with month and year symbols retrieved from NSDateFormatter
.

- 20,509
- 6
- 47
- 58
Rewritten answer of RossP in Swift 4:
import Foundation
@objc class ShortDatePickerView: UIPickerView {
enum Component: Int {
case Month = 0
case Year = 1
}
let LABEL_TAG = 43
let bigRowCount = 1000
let numberOfComponentsRequired = 2
let months = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"]
var years: [String] {
get {
var years: [String] = [String]()
for i in minYear...maxYear {
years.append("\(i)")
}
return years;
}
}
var bigRowMonthsCount: Int {
get {
return bigRowCount * months.count
}
}
var bigRowYearsCount: Int {
get {
return bigRowCount * years.count
}
}
var monthSelectedTextColor: UIColor?
var monthTextColor: UIColor?
var yearSelectedTextColor: UIColor?
var yearTextColor: UIColor?
var monthSelectedFont: UIFont?
var monthFont: UIFont?
var yearSelectedFont: UIFont?
var yearFont: UIFont?
let rowHeight: NSInteger = 44
/**
Will be returned in user's current TimeZone settings
**/
var date: Date {
get {
let month = self.months[selectedRow(inComponent: Component.Month.rawValue) % months.count]
let year = self.years[selectedRow(inComponent: Component.Year.rawValue) % years.count]
let formatter = DateFormatter()
formatter.dateFormat = "MM yyyy"
return formatter.date(from: "\(month) \(year)")!
}
}
var minYear: Int!
var maxYear: Int!
override init(frame: CGRect) {
super.init(frame: frame)
loadDefaultParameters()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadDefaultParameters()
}
override func awakeFromNib() {
super.awakeFromNib()
loadDefaultParameters()
}
func loadDefaultParameters() {
minYear = Calendar.current.dateComponents([.year], from: Date()).year
maxYear = minYear! + 10
self.delegate = self
self.dataSource = self
monthSelectedTextColor = .blue
monthTextColor = .black
yearSelectedTextColor = .blue
yearTextColor = .black
monthSelectedFont = .boldSystemFont(ofSize: 17)
monthFont = .boldSystemFont(ofSize: 17)
yearSelectedFont = .boldSystemFont(ofSize: 17)
yearFont = .boldSystemFont(ofSize: 17)
}
func setup(minYear: NSInteger, andMaxYear maxYear: NSInteger) {
self.minYear = minYear
if maxYear > minYear {
self.maxYear = maxYear
} else {
self.maxYear = minYear + 10
}
}
func selectToday() {
selectRow(todayIndexPath.row, inComponent: Component.Month.rawValue, animated: false)
selectRow(todayIndexPath.section, inComponent: Component.Year.rawValue, animated: false)
}
var todayIndexPath: NSIndexPath {
get {
var row = 0.0
var section = 0.0
for cellMonth in months {
if cellMonth == currentMonthName {
row = Double(months.index(of: cellMonth)!)
row = row + Double(bigRowMonthsCount / 2)
break
}
}
for cellYear in years {
if cellYear == currentYearName {
section = Double(years.index(of: cellYear)!)
section = section + Double(bigRowYearsCount / 2)
break
}
}
return NSIndexPath(row: Int(row), section: Int(section))
}
}
var currentMonthName: String {
get {
let formatter = DateFormatter()
let locale = Locale.init(identifier: "en_US")
formatter.locale = locale
formatter.dateFormat = "MM"
return formatter.string(from: Date())
}
}
var currentYearName: String {
get {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy"
return formatter.string(from: Date())
}
}
func selectedColorForComponent(component: NSInteger) -> UIColor {
if component == Component.Month.rawValue {
return monthSelectedTextColor!
}
return yearSelectedTextColor!
}
func colorForComponent(component: NSInteger) -> UIColor {
if component == Component.Month.rawValue {
return monthTextColor!
}
return yearTextColor!
}
func selectedFontForComponent(component: NSInteger) -> UIFont {
if component == Component.Month.rawValue {
return monthSelectedFont!
}
return yearSelectedFont!
}
func fontForComponent(component: NSInteger) -> UIFont {
if component == Component.Month.rawValue {
return monthFont!
}
return yearFont!
}
func titleForRow(row: Int, forComponent component: Int) -> String? {
if component == Component.Month.rawValue {
return self.months[row % self.months.count]
}
return self.years[row % self.years.count]
}
func labelForComponent(component: NSInteger) -> UILabel {
let frame = CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height: CGFloat(rowHeight))
let label = UILabel(frame: frame)
label.textAlignment = .center
label.backgroundColor = .clear
label.isUserInteractionEnabled = false
label.tag = LABEL_TAG
return label
}
}
extension ShortDatePickerView: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return numberOfComponentsRequired
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if (component == Component.Month.rawValue) {
return bigRowMonthsCount
} else {
return bigRowYearsCount
}
}
func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
return self.bounds.size.width / CGFloat(numberOfComponentsRequired)
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
var selected = false
if component == Component.Month.rawValue {
let monthName = self.months[(row % self.months.count)]
if monthName == currentMonthName {
selected = true
}
} else {
let yearName = self.years[(row % self.years.count)]
if yearName == currentYearName {
selected = true
}
}
var returnView: UILabel
if view?.tag == LABEL_TAG {
returnView = view as! UILabel
} else {
returnView = labelForComponent(component: component)
}
returnView.font = selected ? selectedFontForComponent(component: component) : fontForComponent(component: component)
returnView.textColor = selected ? selectedColorForComponent(component: component) : colorForComponent(component: component)
returnView.text = titleForRow(row: row, forComponent: component)
return returnView
}
func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return CGFloat(rowHeight)
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
}

- 756
- 1
- 9
- 16
I have a lazy workaround-- I made a 10x10 black png. I then used that as a mask with a scaletofill imageview sized to cover the dates column perfectly. I put the alpha at 0.75 to barely show that column. It is clear to the user and looks decent.

- 632
- 6
- 21
-
12Beware of localizing. The dates column is not always the second one; here in France we format dates like this: dd/MM/yyyy, so the picker reads something like [ 16 | février | 2012 ] – Cyrille Feb 16 '12 at 09:50
-
Good point, you would have to move it accordingly if supporting localization, which we were not. At that point, you might as well override the picker methods as Noah said, however it won't be clear to the user what is going on, so you might as well make your own custom picker! – Mischa Feb 16 '12 at 23:29
I'm using a simple UIPickerView
with 2 components (months and years).
And calling the UIPickerViewDelegate
with every row selection:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
//Today year and month
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy"];
int year = [[dateFormat stringFromDate:[NSDate date]] intValue];
[dateFormat setDateFormat:@"MM"];
int month = [[dateFormat stringFromDate:[NSDate date]] intValue] - 1;
//picker year and month
int selectedYear = [[self.yearsArray objectAtIndex:[pickerView selectedRowInComponent:1]] intValue];
int selectedMonth = [pickerView selectedRowInComponent:0];
// if month in the past, change the month
if (year == selectedYear && selectedMonth < month)
{
[pickerView selectRow:month inComponent:0 animated:YES];
}
}

- 3,976
- 9
- 30
- 39

- 8,165
- 6
- 62
- 81
-
2Perhaps have the NSDateFormatter as an ivar rather than initialise a new one each time a row is selected. – theiOSDude Mar 21 '14 at 11:57
I just reset the day to first of the month when the value change event happens as below. So When the user selects a day, it scrolls back to 1st. I use following for selecting Start date (month & year).
-(void) resetDay {
NSDate *currentDate = [startDatePicker date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsYear = [gregorian components:(NSYearCalendarUnit| NSMonthCalendarUnit) fromDate:currentDate];
NSInteger yearNum = [ componentsYear year];
NSInteger monthNum = [componentsYear month];
NSLog(@"Month %d, Year %d", monthNum, yearNum);
NSDateComponents *componentStartDate = [[NSDateComponents alloc] init];
[componentStartDate setDay:1];
[componentStartDate setMonth:monthNum];
[componentStartDate setYear:yearNum];
NSDate *startDate = [gregorian dateFromComponents:componentStartDate];
[startDatePicker setDate:startDate animated:YES];
[componentStartDate release];
[gregorian release];
}
For selecting the End Date (month & year) it is little bit longer, because I wanted to set the day to 31st or 30th of the month selected.
-(NSInteger) findDaysInYear {
NSDate *currentDate = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsYear = [gregorian components:(NSYearCalendarUnit) fromDate:currentDate];
NSInteger yearNum = [ componentsYear year];
NSDateComponents *componentStartDate = [[NSDateComponents alloc] init];
[componentStartDate setDay:1];
[componentStartDate setMonth:1];
[componentStartDate setYear:yearNum];
NSDate *startDate = [gregorian dateFromComponents:componentStartDate];
NSLog(@"Start date set to %@", startDate);
NSDateComponents *componentEndDate = [[NSDateComponents alloc] init];
[componentEndDate setDay:31];
[componentEndDate setMonth:12];
[componentEndDate setYear:yearNum];
NSDate *endDate = [gregorian dateFromComponents:componentEndDate];
NSLog(@"End date set to %@", endDate);
NSUInteger unitFlags = NSDayCalendarUnit ;
NSDateComponents *componentsDay = [gregorian components:unitFlags fromDate:startDate toDate:endDate options:0];
NSInteger days = [componentsDay day] +1;
NSLog(@"Number of days in the year:%d, is %d", yearNum,days);
[componentEndDate release];
[componentStartDate release];
[gregorian release];
if (days != 365 && days != 366) {
return 366;
}
return days;
}
-(NSInteger) findDaysInMonth:(NSInteger) monthNum {
NSInteger days = 30;
switch (monthNum) {
case 1:
days = 31;
break;
case 2:
if([self findDaysInYear] == 366) days = 29;
else days = 28;
break;
case 3:
days = 31;
break;
case 4:
days = 30;
break;
case 5:
days = 31;
break;
case 6:
days = 30;
break;
case 7:
days = 31;
break;
case 8:
days = 31;
break;
case 9:
days = 30;
break;
case 10:
days = 31;
break;
case 11:
days = 30;
break;
case 12:
days = 31;
break;
default:
break;
}
return days;
}
-(void) resetDay {
NSDate *currentDate = [endDatePicker date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsYear = [gregorian components:(NSYearCalendarUnit| NSMonthCalendarUnit) fromDate:currentDate];
NSInteger yearNum = [ componentsYear year];
NSInteger monthNum = [componentsYear month];
NSDateComponents *componentStartDate = [[NSDateComponents alloc] init];
[componentStartDate setDay:[self findDaysInMonth:monthNum]];
[componentStartDate setMonth:monthNum];
[componentStartDate setYear:yearNum];
NSDate *startDate = [gregorian dateFromComponents:componentStartDate];
[endDatePicker setDate:startDate animated:YES];
[componentStartDate release];
[gregorian release];
}

- 1,514
- 13
- 14
You can use the open source library named
AKMonthYearPickerView
import AKMonthYearPickerView
AKMonthYearPickerView.sharedInstance.show(vc: viewController, doneHandler: doneHandler, completetionalHandler: completetionalHandler)
https://github.com/ali-cs/AKMonthYearPickerView
to install it using pods,
pod 'AKMonthYearPickerView'
to customize previous years limit and bar color
AKMonthYearPickerView.sharedInstance.barTintColor = UIColor.blue
AKMonthYearPickerView.sharedInstance.previousYear = 4

- 1,102
- 5
- 21
- 39
You can use UICustomDatePicker to show only the month and year option
https://github.com/Anandsan/UICustomDatePicker
@interface ViewController ()
@property (nonatomic, weak) IBOutlet UICustomDatePicker *customDatePicker;
@end
-(void) viewDidLoad {
[super viewDidLoad];
self.customDatePicker.option = NSCustomDatePickerOptionLongMonth | NSCustomDatePickerOptionYear;
self.customDatePicker.order = NSCustomDatePickerOrderMonthDayAndYear;
}
-(IBAction)didCustomDatePickerValueChanged:(id)sender {
NSLog(@"%@",[(UICustomDatePicker *)sender currentDate]);
}

- 401
- 1
- 5
- 13

- 1
- 2
-
Welcome to SO :) Please do not answer with **just** a link. Add also an explanation and/or some code to improve the quality of your answer. – Ivan Gabriele Jul 05 '16 at 21:55
I have rewrote MonthYearPicker project with custom minDate, maxDate, blurred effect background and show up picker animation: MonthYearPicker

- 726
- 8
- 12
You can very easily hide the day column like this:
datePicker.subviews[0].subviews[0].subviews[1].hidden = true
Enjoy :)

- 137
- 6
-
1@CanAksoy ok! It maybe didn't work! But what was your problem exactly? I just found out that it matters what is the _NSLocale_ of the _UIDatePicker_. The third set of subviews are the columns [month][day][year]. However for French for instance it would be [day][month][year] and my solution above would hide the month column and show the day column. So for example if you want to hide the day column for French set UIDatePicker you would do this `datePicker.subviews[0].subviews[0].subviews[0].hidden = true`. You can also move the month column a bit `....subviews[1].frame.origin.x -= 50.0` – dizza213 Mar 07 '16 at 14:18
-
1While this may very well work, it is highly not recommended (hence, the downvotes). You should never mess around with the iOS standard controls like this, because you have no guarantee that it will remain at this exact hierarchy-index after the next iOS update. Rather (as most of the other answers suggests) inherit the default UIPickerView and give it a Delegate that serves the needs for only a month and year. – Falgantil Jun 24 '16 at 14:49
-
1Sorry but down-voters hate on me cause it's one-line simple solution that they couldn't come up with it ;) Peace out! – dizza213 Jun 25 '16 at 15:28