Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIDatePicker strange behaviour with Islamic calendar

Note: Bug reported to Apple

Radar number: 29265429 (Link)

I am using a UIDatePicker. When I give Gregorian calendar it works fine. The days starts from 1 to 31

However, when I give it Islamic islamicUmmAlQura it gives me a strange behaviour. The days starts from 1 to 30 but there is a '2' above 1 and below 30 such that days are as follows 2,1,2,3,4 ... 30

I have created a new empty iOS project and placed the following code into the viewDidLoad method:

let picker = UIDatePicker(frame: CGRect(x: 0, y: 30, width: 0, height: 0))

picker.datePickerMode = .date
picker.date = Date()
picker.calendar = Calendar(identifier: .islamicUmmAlQura)
picker.autoresizingMask = UIViewAutoresizing.flexibleRightMargin
picker.frame.size.width = 300
view.addSubview(picker)

Screenshot:

enter image description here

like image 932
malhobayyeb Avatar asked Nov 13 '16 07:11

malhobayyeb


1 Answers

It is not that hard to make your own UIPicker that looks like a UIDatePicker, but you have to be careful because the bug is in NSCalendar as well as NSDatePicker.

Just to be clear the extra '2' is not selectable, just like 30 is not selectable in a short month. NSDatePicker does not hide invalid days or months, but makes them unselectable. So in the Gregorian calendar if you select February you will still see 29, 30, and 31, but trying to select them the picker will got to 28. The DataPicker figures out how many months and days to show by calling maximumRangeOfUnit: on the calendar. In an Islamic calendar the correct maximum is {1, 30}, but NSCalendar returns {1,31} for maximumRangeOfUnit:NSCalendarUnitDay for all Islamic calendars.

So there are two bugs. One is that NSCalendar is saying that there can be 31 days in an Islamic Month (which I don't believe is true), and the second issue is that NSDatePicker is showing the 31st day a 2 instead of 31.

Making your own NSDatePicker is really not that hard. The amount of element in each component is always the same (just make sure to manually set 30 for the days and not use the value from NSCalendar). The tricky part is deciding if a date is invalid and showing the element as gray and not letting the picket rest on it. You can use rangeOfUnit:InUnit:forDate to get the number of days in a month or number of months in a year. If an invalid element get selected them move the value down to the highest valid date (ie if a user selects 30 in a month with 29 days select 29).

Once a row is selected you can convert from day-month-year to an NSDate with dateFromComponents on NSCalendar.

like image 151
Jon Rose Avatar answered Nov 16 '22 14:11

Jon Rose