Pavan
Pavan

Reputation: 18508

How to programmatically check the date format of a string for correct formatting

Take this time timestamp for example. 1993-11-14T00:00:00.000Z

I have tried to use the following date formats in an attempt to convert the string to an NSDate object but I keep failing as I have not supplied the right formatting. Is there anyway to make a programmtic check, maybe a parser that will do this automatically for me?

NSDateFormatter *inputDateFormat = [[NSDateFormatter alloc] init];
//Not correct format
[inputDateFormat setDateFormat:@"yyyy-MM-ddTHH:mm:ssZ"];
self.usersBirthDate = [inputDateFormat dateFromString:[dictionary objectForKey:@"birth_date"]];

}

Upvotes: 2

Views: 1182

Answers (1)

Rob
Rob

Reputation: 437702

You should identify the correct format string and use it. In this case, the correct format string is:

yyyy-MM-dd'T'HH:mm:ss.SSSZ

Note, the single quotes around the T and add the .SSS milliseconds to the end. BTW, don't forget to set the locale as discussed in Technical Q&A QA1480.


In answer to your question, one promising alternative is to use NSDataDetector with a type of NSTextCheckingTypeDate. Surprisingly, it actually captures quite a few ISO 8601/RFC 3339 date permutations. Sadly, it doesn't handle the permutation with milliseconds.

But it wouldn't be hard to write a routine that does what you describe, though. You could employ regular expressions, e.g. something like:

- (NSDate *)dateFromString:(NSString *)string {
    static NSArray *formatStrings = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        formatStrings = @[@{kDateFormatRegex: @"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}$",    kDateFormatString: @"yyyy-MM-dd'T'HH:mm:ss.SSS"},
                          @{kDateFormatRegex: @"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",             kDateFormatString: @"yyyy-MM-dd'T'HH:mm:ss"},
                          @{kDateFormatRegex: @"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$",   kDateFormatString: @"yyyy-MM-dd'T'HH:mm:ss.SSSZ"},
                          @{kDateFormatRegex: @"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$",            kDateFormatString: @"yyyy-MM-dd'T'HH:mm:ssZ"},
                          @{kDateFormatRegex: @"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}[A-Z]{3}$",     kDateFormatString: @"yyyy-MM-dd'T'HH:mm:ssz"},
                          @{kDateFormatRegex: @"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2} [A-Z]{3}$",    kDateFormatString: @"yyyy-MM-dd'T'HH:mm:ss z"},
                          @{kDateFormatRegex: @"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2} [+|-]\\d{4}$", kDateFormatString: @"yyyy-MM-dd'T'HH:mm:ss Z"}];
    });

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
    formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    for (NSDictionary *dictionary in formatStrings) {
        if ([string rangeOfString:dictionary[kDateFormatRegex] options:NSRegularExpressionSearch].location != NSNotFound) {
            formatter.dateFormat = dictionary[kDateFormatString];
            return [formatter dateFromString:string];
        }
    }

    return nil;
}

Having said all of that, this seems like a very inefficient process: It strikes me that it would be much better to know which format your web service was going to employ for dates and use the appropriate format string for that. But if you wanted to detect the pattern programmatically, you could use regular expressions like above. Just expand that dictionary of formatStrings to include all the possible permutations you care about.

Upvotes: 5

Related Questions