4
\$\begingroup\$

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;
}
\$\endgroup\$
  • \$\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 Oct 26 '12 at 13:21
  • \$\begingroup\$ I think [calendar dateFromComponents:correctAge] (third line from bottom) may crash.. \$\endgroup\$ – rdurand Oct 26 '12 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 Oct 26 '12 at 14:17
  • \$\begingroup\$ Well, I think you're good then ! \$\endgroup\$ – rdurand Oct 29 '12 at 8:44
2
\$\begingroup\$

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];
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Can you give a brief description of what this method is doing? \$\endgroup\$ – Jeff Vanzella Aug 28 '13 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 Sep 12 '13 at 8:10
  • \$\begingroup\$ It would be better to NSInteger for the numYears argument to better deal with 32bit/64bit differences (iPhone 5S was just announced to be 64 bit). Also, numYears is passed to setYear: which takes an NSInteger. \$\endgroup\$ – David Rönnqvist Sep 12 '13 at 8:13
1
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.