如何解析Objective C中的ISO-8601持续时间?

Zar*_*ony 14 iphone datetime objective-c iso8601 nstimeinterval

我正在寻找一种简单的方法来解析在Objective C 中包含ISO-8601 持续时间的字符串.结果应该是像a一样可用的东西NSTimeInterval.

ISO-8601持续时间的一个示例:P1DT13H24M17S表示1天,13小时,24分钟和17秒.

hea*_*aze 10

一个纯粹的Objective C版本......

NSString *duration = @"P1DT10H15M49S";

int i = 0, days = 0, hours = 0, minutes = 0, seconds = 0;

while(i < duration.length)
{
    NSString *str = [duration substringWithRange:NSMakeRange(i, duration.length-i)];

    i++;

    if([str hasPrefix:@"P"] || [str hasPrefix:@"T"])
        continue;

    NSScanner *sc = [NSScanner scannerWithString:str];
    int value = 0;

    if ([sc scanInt:&value])
    {
        i += [sc scanLocation]-1;

        str = [duration substringWithRange:NSMakeRange(i, duration.length-i)];

        i++;

        if([str hasPrefix:@"D"])
            days = value;
        else if([str hasPrefix:@"H"])
            hours = value;
        else if([str hasPrefix:@"M"])
            minutes = value;
        else if([str hasPrefix:@"S"])
            seconds = value;
    }
}

NSLog(@"%@", [NSString stringWithFormat:@"%d days, %d hours, %d mins, %d seconds", days, hours, minutes, seconds]);
Run Code Online (Sandbox Code Playgroud)


Ser*_*kar 7

此版本解析每个youtube持续时间没有错误.
重要提示:此版本使用ARC.

- (NSString*)parseISO8601Time:(NSString*)duration
{
    NSInteger hours = 0;
    NSInteger minutes = 0;
    NSInteger seconds = 0;

    //Get Time part from ISO 8601 formatted duration http://en.wikipedia.org/wiki/ISO_8601#Durations
    duration = [duration substringFromIndex:[duration rangeOfString:@"T"].location];

    while ([duration length] > 1) { //only one letter remains after parsing
        duration = [duration substringFromIndex:1];

        NSScanner *scanner = [[NSScanner alloc] initWithString:duration];

        NSString *durationPart = [[NSString alloc] init];
        [scanner scanCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] intoString:&durationPart];

        NSRange rangeOfDurationPart = [duration rangeOfString:durationPart];

        duration = [duration substringFromIndex:rangeOfDurationPart.location + rangeOfDurationPart.length];

        if ([[duration substringToIndex:1] isEqualToString:@"H"]) {
            hours = [durationPart intValue];
        }
        if ([[duration substringToIndex:1] isEqualToString:@"M"]) {
            minutes = [durationPart intValue];
        }
        if ([[duration substringToIndex:1] isEqualToString:@"S"]) {
            seconds = [durationPart intValue];
        }
    }

    return [NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
}
Run Code Online (Sandbox Code Playgroud)


Igo*_*uta 7

Swift2实现:https://github.com/Igor-Palaguta/YoutubeEngine/blob/swift-2.3/YoutubeEngine/Classes/Parser/NSDateComponents+ISO8601.swift

例: let components = NSDateComponents(ISO8601String: "P1Y2M3DT4H5M6S")

测试:https://github.com/Igor-Palaguta/YoutubeEngine/blob/swift-2.3/Example/Tests/ISO8601DurationTests.swift

它还正确处理"P1M"和"PT1M"情况

Swift3实现:https: //github.com/Igor-Palaguta/YoutubeEngine/blob/master/Source/YoutubeEngine/Parser/NSDateComponents%2BISO8601.swift

例: let components = dateComponents(ISO8601String: "P1Y2M3DT4H5M6S")

测试:https: //github.com/Igor-Palaguta/YoutubeEngine/blob/master/Tests/YoutubeEngineTests/ISO8601DurationTests.swift

2017年1月20日更新:增加了数周的支持

  • @DougSmith,感谢您的反馈。添加了对周的支持,您现在可以使用 weekOfYear 属性来获取周 (2认同)

Ada*_*eld 6

如果您确切知道将要获得哪些字段,则可以使用以下调用sscanf():

const char *stringToParse = ...;
int days, hours, minutes, seconds;
NSTimeInterval interval;
if(sscanf(stringToParse, "P%dDT%dH%dM%sS", &days, &hours, &minutes, &seconds) == 4)
    interval = ((days * 24 + hours) * 60 + minutes) * 60 + seconds;
else
    ; // handle error, parsing failed
Run Code Online (Sandbox Code Playgroud)

如果可以省略任何字段,则需要在解析时更加智能,例如:

const char *stringToParse = ...;
int days = 0, hours = 0, minutes = 0, seconds = 0;

const char *ptr = stringToParse;
while(*ptr)
{
    if(*ptr == 'P' || *ptr == 'T')
    {
        ptr++;
        continue;
    }

    int value, charsRead;
    char type;
    if(sscanf(ptr, "%d%c%n", &value, &type, &charsRead) != 2)
        ;  // handle parse error
    if(type == 'D')
        days = value;
    else if(type == 'H')
        hours = value;
    else if(type == 'M')
        minutes = value;
    else if(type == 'S')
        seconds = value;
    else
        ;  // handle invalid type

    ptr += charsRead;
}

NSTimeInterval interval = ((days * 24 + hours) * 60 + minutes) * 60 + seconds;
Run Code Online (Sandbox Code Playgroud)

  • 上面的代码示例要记住一件小事(是的,我意识到这可能是为了证明一点而不是实际消费).ISO 8601标准允许将持续时间值指定为可由"."分隔的小数值(即1.5,0.6等).要么 ",". (2认同)