I'm creating some age-verification functionality for an iOS app. The user is presented with a UIDatePicker
object, and the latest selectable date should be today minus 18 years. How vulnerable to inaccuracy is my code? How could it be leaner?
-(void)validateAge {
NSDateComponents *today = [[NSCalendar currentCalendar] components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:[NSDate date]];
NSInteger day = [today day];
NSInteger month = [today month];
NSInteger year = [today year];
int correctYear = year - 18;
NSDateComponents *correctAge = [[NSDateComponents alloc] init];
[correctAge setDay:day];
[correctAge setMonth:month];
[correctAge setYear:correctYear];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
UIDatePicker *agePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 240, 320, 200)];
[agePicker setDatePickerMode:UIDatePickerModeDate];
[agePicker setMaximumDate:[calendar dateFromComponents:correctAge]];
[self.view addSubview:agePicker];
return;
}
-
\$\begingroup\$ Well, first of all, what about leap years ? If someone uses it on the 29th of february on a leap year, february 18 years earlier will always be 28 days long. I don't know what will happen with your code though, but I'd suggest to set up a test scenario for this situation.. \$\endgroup\$rdurand– rdurand2012年10月26日 13:21:40 +00:00Commented Oct 26, 2012 at 13:21
-
\$\begingroup\$ I think [calendar dateFromComponents:correctAge] (third line from bottom) may crash.. \$\endgroup\$rdurand– rdurand2012年10月26日 13:23:28 +00:00Commented Oct 26, 2012 at 13:23
-
\$\begingroup\$ That's an interesting point. I tested it by setting my system date to 29/02/2012. My datepicker set the maximum date to 01/03/1994. I think that's acceptable from a legal standpoint, as 'leaplings' can either have their birthdays on February 28th or March 1st. The app I implemented this in has been tested fairly extensively on a number of devices; no crashes yet. \$\endgroup\$Jezen Thomas– Jezen Thomas2012年10月26日 14:17:44 +00:00Commented Oct 26, 2012 at 14:17
-
\$\begingroup\$ Well, I think you're good then ! \$\endgroup\$rdurand– rdurand2012年10月29日 08:44:27 +00:00Commented Oct 29, 2012 at 8:44
2 Answers 2
Check this method. Pass value as minus 18 (-18)
-(NSDate *)offsetYear:(int)numOfYears date:(NSDate*)date {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setYear:numOfYears];
return [gregorian dateByAddingComponents:offsetComponents
toDate:date options:0];
}
-
1\$\begingroup\$ Can you give a brief description of what this method is doing? \$\endgroup\$Jeff Vanzella– Jeff Vanzella2013年08月28日 21:43:17 +00:00Commented Aug 28, 2013 at 21:43
-
\$\begingroup\$ @JeffVanzella It offsets the the specific date by
numYears
in the Gregorian calendar. For example if you will pass-18
it will go back 18 years (and deal with leap years correctly). \$\endgroup\$David Rönnqvist– David Rönnqvist2013年09月12日 08:10:58 +00:00Commented Sep 12, 2013 at 8:10 -
\$\begingroup\$ It would be better to
NSInteger
for thenumYears
argument to better deal with 32bit/64bit differences (iPhone 5S was just announced to be 64 bit). Also,numYears
is passed tosetYear:
which takes anNSInteger
. \$\endgroup\$David Rönnqvist– David Rönnqvist2013年09月12日 08:13:43 +00:00Commented Sep 12, 2013 at 8:13
One basic idea about human-computer interaction is that a user should always be able to select something on the interface and go forward somewhere. You don't want to just leave them 'on hold'.
In your implementation, if the user is under 18, the interface will force them to lie about their birth date.
A much better idea would be to allow the user to select any date, but compute the difference in years to perform different operations depending upon the difference. You do this using
NSDateComponents *components = [calendar components:NSYearCalendarUnit
fromDate:enteredDate
toDate:[Date new] // today
options:0];
After that, for people under 18, you can e.g. display an alert and redirect them to a different app.
It would still be possible for users to lie about their birth dates, of course, but the interface will not encourage it as much.