NSDateFormatter and timezone format strings "+ HH: mm"

Update

Like iOS 7, NSDateFormatter does create an NSDate when presenting a string in this format:

NSDateFormatter *formatter = [NSDateFormatter new]; [formatter setDateFormat:@"@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ""]; NSLog(@"non–nil date, even honoring the 7–minute–offset in the time–zone on iOS 7: %@", [formatter dateFromString:@"2011-07-12T18:07:31+02:07"]); 

For iOS 6, the answer is not to use NSDateFormatter ...


Ok, up to this point i read

regarding the use of NSDateFormatter to create an NSDate from a string.

I came across Peter Hosey ISO8601DateFormatter as well. Looking into its implementation, I wonder:

Is there a way that is right and right to get a line like this 2011-07-12T18:07:31+02:00 in NSDate ?

  • There would be no problem if the last colon was missing.
  • There would be no problems if there was GMT , the prefix of the "+" sign, but ...
  • This is not true.

I can hack it to work for my application (using the format @"yyyy'-'MM'-'dd'T'HH':'mm':'ssz':'00" ), but this - of course - is wrong , because that he will discard minute time zone information.

I could also replace the last colon with an empty string, but I would also think it was a hack.

So, is there any secret sauce so that NSDateFormatter takes this line on top and gives me the correct and correct NSDate ?


To the side:

I found a hint somewhere that you can use +[NSDate dateWithNaturalLanguageString:] to achieve my goal. This - however - only sets the date, not the time! (Well, this sets the time, but only considers the time zone offset, not HH: mm: ss part ...)

+6
source share
2 answers

This question is a bit outdated, but I had the same problem. I came up with code that is the answer and may be useful to others ...

I use the regexp to parse an ISO-8601 string and grab the output into a string chain, which you can then use to create your own string to go to NSDateFormatter (i.e. removing colons, etc.) or if you always want the same output line, just create this from the results of the call in NSRegularExpression.

 // ISO-8601 regex: // YYYY-MM-DDThh:mm[:ss[.nnnnnnn]][{+|-}hh:mm] // Unfortunately NSDateFormatter does not parse iso-8601 out of the box, // so we need to use a regex and build up a date string ourselves. static const char * REGEX_ISO8601_TIMESTAMP = "\\A(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2})" // Mandatory - YYYY-MM-DDThh:mm "(?:" ":(\\d{2})" // Optional - :ss "(?:" "[.](\\d{1,6})" // Optional - .nnnnnn ")?" ")?" "(?:" "([+-])(\\d{2}):(\\d{2})|Z" // Optional -[+-]hh:mm or Z ")?\\z"; // Extract all the parts of the timestamp NSError *error = NULL; NSString *regexString = [[NSString alloc] initWithUTF8String:REGEX_ISO8601_TIMESTAMP]; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:NSRegularExpressionCaseInsensitive error:&error]; NSArray *matches = [regex matchesInString:timestamp options:0 range:NSMakeRange(0, [timestamp length])]; // Groups: // // elements start at 1 in the array returned from regex, as [0] contains the original string. // // MANDATORY - must exist as per ISO standard // 1 - YYYY // 2 - MM // 3 - DD // 4 - hh // 5 - mm // OPTIONAL (each one can be optional) // 6 - ss // 7 - nn (microseconds) // 8 - offset sign (+/-) // 9 - offset hour // 10 - offset min // put the parts into a string which will then be recognised by NSDateFormatter // (which is acutally RFC822 format) // mandatory init'd to nil, optional set to defaults. NSString *YYYY, *MM, *DD, *hh, *mm, *ss, *nn, *sign, *Zhh, *Zmm; NSRange tempRange; for (NSTextCheckingResult *match in matches) { NSRange matchRange = [match range]; NSInteger matchCount = [match numberOfRanges] - 1; NSUInteger idx = 1; if (idx < matchCount) { tempRange = [match rangeAtIndex:idx++]; YYYY = tempRange.location != NSNotFound ? [timestamp substringWithRange:tempRange] : nil; } if (idx < matchCount) { tempRange = [match rangeAtIndex:idx++]; MM = tempRange.location != NSNotFound ? [timestamp substringWithRange:tempRange] : nil; } if (idx < matchCount) { tempRange = [match rangeAtIndex:idx++]; DD = tempRange.location != NSNotFound ? [timestamp substringWithRange:tempRange] : nil; } if (idx < matchCount) { tempRange = [match rangeAtIndex:idx++]; hh = tempRange.location != NSNotFound ? [timestamp substringWithRange:tempRange] : nil; } if (idx < matchCount) { tempRange = [match rangeAtIndex:idx++]; mm = tempRange.location != NSNotFound ? [timestamp substringWithRange:tempRange] : nil; } if (idx < matchCount) { tempRange = [match rangeAtIndex:idx++]; ss = tempRange.location != NSNotFound ? [timestamp substringWithRange:tempRange] : nil; } if (idx < matchCount) { tempRange = [match rangeAtIndex:idx++]; nn = tempRange.location != NSNotFound ? [timestamp substringWithRange:tempRange] : nil; } if (idx < matchCount) { tempRange = [match rangeAtIndex:idx++]; sign = tempRange.location != NSNotFound ? [timestamp substringWithRange:tempRange] : nil; } if (idx < matchCount) { tempRange = [match rangeAtIndex:idx++]; Zhh = tempRange.location != NSNotFound ? [timestamp substringWithRange:tempRange] : nil; } if (idx < matchCount) { tempRange = [match rangeAtIndex:idx++]; Zmm = tempRange.location != NSNotFound ? [timestamp substringWithRange:tempRange] : nil; } } 

Hope this helps someone!

+2
source

Old question, but I found the correct answer to the question:

https://gist.github.com/soffes/840291

It parses and creates ISO-8601 strings, and it's faster than NSDateFormatter

Here is the code:

 + (NSDate *)dateFromISO8601String:(NSString *)string { if (!string) { return nil; } struct tm tm; time_t t; strptime([string cStringUsingEncoding:NSUTF8StringEncoding], "%Y-%m-%dT%H:%M:%S%z", &tm); tm.tm_isdst = -1; t = mktime(&tm); return [NSDate dateWithTimeIntervalSince1970:t + [[NSTimeZone localTimeZone] secondsFromGMT]]; } - (NSString *)ISO8601String { struct tm *timeinfo; char buffer[80]; time_t rawtime = [self timeIntervalSince1970] - [[NSTimeZone localTimeZone] secondsFromGMT]; timeinfo = localtime(&rawtime); strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S%z", timeinfo); return [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding]; } 
+1
source

Source: https://habr.com/ru/post/892597/


All Articles