Murdock
Murdock

Reputation: 866

Reliably checking whether NSDate falls within given hour, day or week

I need to take a stored NSDate and reliably determine whether it falls within the current moment's hour, day or week. I seem to have hacked together a solution, but not having solved this problem before, am not entirely confident that it's a reliable one.

Will this survive user-set 12 vs 24 hour time? the date formatting guide indicates that this user setting can lead to some unanticipated date behavior: "In iOS, the user can override the default AM/PM versus 24-hour time setting. This may cause NSDateFormatter to rewrite the format string you set."

What about the basic code pattern for this problem? Does this code seem to reliably serve its purpose? I hate to post a "check my code" sort of question, but it's an unfamiliar-enough problem to me, and tricky enough to rigorously test, that it seemed justified. NSDateFormatter is also relatively new to me; another motivation for the question.

NOTE: The main source of my nervousness is that converting dates to strings and then doing a string compare seems an inherently fragile method of solving this problem. But it's the best I could come up with.

Quick reference: the dateFormats I used for each of the three cases were:

dateFormat = @"yyyyMMddHH"; // For "this hour" check
dateFormat = @"yyyyMMdd"; // For "today" check
dateFormat = @"yyyyww"; // For "this week" check 

Thanks! Code Follows:

- (BOOL)didThisCycle {
    // Case 1: hourly; Case 2: daily; Case 3: weekly
    BOOL did = NO;

    NSDate *now = [NSDate date];
    NSDate *lastDid = [self.didDates lastObject];

    if (![lastDid isKindOfClass:[NSDate class]]) { // Crash protection
        return NO;
    }

    int type = [self.goalType intValue];
    switch (type) {
        case 1:
        {
            // If hourly check hour
            NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
            formatter.dateFormat = @"yyyyMMddHH";
            NSString *nowString = [formatter stringFromDate:now];
            NSString *lastDidString = [formatter stringFromDate:lastDid];
            if ([nowString isEqualToString:lastDidString]) {
                did = YES;
            } else {
                did = NO;
            }
            break;
        }
        case 2:
        {
            // If daily check day
            NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
            formatter.dateFormat = @"yyyyMMdd";
            NSString *nowString = [formatter stringFromDate:now];
            NSString *lastDidString = [formatter stringFromDate:lastDid];
            if ([nowString isEqualToString:lastDidString]) {
                did = YES;
            } else {
                did = NO;
            }
            break;
        }
        case 3:
        {
            // If weekly check week
            NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
            formatter.dateFormat = @"yyyyww";
            NSString *nowString = [formatter stringFromDate:now];
            NSString *lastDidString = [formatter stringFromDate:lastDid];
            if ([nowString isEqualToString:lastDidString]) {
                did = YES;
            } else {
                did = NO;
            }
            break;
        }
        default:
        {
            did = NO;
            break;
        }
    }

    return did;
}

Upvotes: 4

Views: 1015

Answers (1)

Noah Witherspoon
Noah Witherspoon

Reputation: 57139

Use the NSDateComponents class, like so:

NSDate *someDate = // whatever
NSDate *now = [NSDate date];
NSDateComponents *thenComponents = [[NSCalendar currentCalendar] components:NSHourCalendarUnit|NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:someDate];
NSDateComponents *nowComponents = [[NSCalendar currentCalendar] components:NSHourCalendarUnit|NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:now];
if([thenComponents year] == [nowComponents year] && [thenComponents month] == [nowComponents month] && [thenComponents day] == [nowComponents day] && [thenComponents hour] == [nowComponents hour])
{
    // hooray
}

Remove the “hour” component if you just want to check the day, or remove both that and “day” (and replace with NSWeekCalendarUnit and the -week method) to check the week.

Upvotes: 7

Related Questions