从iOS 7开始,NSDateFormatter 确实在呈现此格式的字符串时确实会创建一个NSDate:
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"]);
对于iOS 6,答案是不使用NSDateFormatter ......
好的,到目前为止我已阅读
关于如何使用NSDateFormatter
来创建字符串中的NSDate
。
我偶然发现了Peter Hosey的ISO8601DateFormatter 看看他的实施,我想知道:
是不是有正确的和正确的方式将2011-07-12T18:07:31+02:00
这样的字符串变成NSDate
?
GMT
前缀为“+” - 符号,那将是没有问题的,但是...... 我可以破解它为我的应用程序工作(使用格式@"yyyy'-'MM'-'dd'T'HH':'mm':'ssz':'00"
)但是 - 当然 - 不正确因为它会丢弃分钟 - 时区信息。
我也可以用空字符串替换最后一个冒号,但我也认为这也是一个黑客。
那么,是否有一些秘密的调料让NSDateFormatter
从上面拿出那个字符串并给我一个有效且正确的NSDate
?
我找到了一个提示,可以使用+[NSDate dateWithNaturalLanguageString:]
来实现我的目标。然而 - 这只是设定日期,而不是时间! (好吧 设置时间,但只考虑时区偏移而不是HH:mm:ss部分......)
答案 0 :(得分:2)
这个问题有点陈旧,但我遇到了同样的问题。我提出了一些代码,这是一个答案,可能对其他人有用......
我使用正则表达式来解析ISO-8601字符串并将输出抓取成一串字符串,然后您可以使用它来创建自己的字符串以传递给NSDateFormatter(即删除冒号等)或者如果您总是想要相同的输出字符串,只需从调用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;
}
}
希望这有助于某人!
答案 1 :(得分:1)
老问题,但我找到了正确的答案:
https://gist.github.com/soffes/840291
它解析并创建ISO-8601字符串,它比NSDateFormatter
以下是代码:
+ (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];
}