NSTimeInterval to HH:mm:ss?

IphoneObjective CCocoa Touch

Iphone Problem Overview


If I have an NSTimeInterval that is set to say 200.0, is there a way to convert that into 00:03:20, I was thinking I could initialise an NSDate with it and then use NSDateFormatter using HH:mm:ss. My question is, is there a quick way to do this or do I have to break up the number myself and use [NSString stringWithFormat: %02d:%02d:%02d, myHour, myMin, mySec]?

Iphone Solutions


Solution 1 - Iphone

No need to use NSDateFormatter or anything else than division and modulo. NSTimeInterval is just a double containing seconds.

Swift

func stringFromTimeInterval(interval: NSTimeInterval) -> String {
    let interval = Int(interval)
    let seconds = interval % 60
    let minutes = (interval / 60) % 60
    let hours = (interval / 3600)
    return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
}

Objective-C

- (NSString *)stringFromTimeInterval:(NSTimeInterval)interval {
    NSInteger ti = (NSInteger)interval;
    NSInteger seconds = ti % 60;
    NSInteger minutes = (ti / 60) % 60;
    NSInteger hours = (ti / 3600);
    return [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes, (long)seconds];
}

Solution 2 - Iphone

On iOS 8, use NSDateComponentsFormatter.

NSDateComponentsFormatter *dateComponentsFormatter = [[NSDateComponentsFormatter alloc] init];
NSLog(@"%@", [dateComponentsFormatter stringFromTimeInterval:200.0]);

outputs "3:20".

NSDateComponentsFormatter *dateComponentsFormatter = [[NSDateComponentsFormatter alloc] init];
dateComponentsFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
dateComponentsFormatter.allowedUnits = (NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond);
NSLog(@"%@", [dateComponentsFormatter stringFromTimeInterval:200.0]);

outputs "0:03:20".

Solution 3 - Iphone

Swift 3 version of onmyway133's answer:

import Foundation

func format(_ duration: TimeInterval) -> String {
    let formatter = DateComponentsFormatter()
    formatter.zeroFormattingBehavior = .pad
    formatter.allowedUnits = [.minute, .second]
    
    if duration >= 3600 {
        formatter.allowedUnits.insert(.hour)
    }
    
    return formatter.string(from: duration)!
}
    

print(format(12)) // 0:12
print(format(65)) // 1:05
print(format(1750)) // 29:10
print(format(3890)) // 1:04:50
print(format(45720)) // 12:42:00

Solution 4 - Iphone

Some extra lines of code, but I feel using NSDateComponents will give a more precise value.

- (NSString *)getTimeRepresentationFromDate:(NSDate *)iDate withTimeInterval:(NSTimeInterval)iTimeInterval {
    NSString *aReturnValue = nil;
    NSDate *aNewDate = [iDate dateByAddingTimeInterval:iTimeInterval]; 
    
    unsigned int theUnits = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    NSCalendar *aCalender = [NSCalendar currentCalendar];
    NSDateComponents *aDateComponents = [aCalender components:theUnits fromDate:iDate toDate:aNewDate options:0];
    
    aReturnValue = [NSString stringWithFormat:@"%d:%d:%d", [aDateComponents hour], [aDateComponents minute], [aDateComponents second]];
    
    return aReturnValue;
}

Solution 5 - Iphone

In Swift 2, iOS 8+. This makes sure we only show hour when necessary

func format(duration: NSTimeInterval) -> String {
  let formatter = NSDateComponentsFormatter()
  formatter.zeroFormattingBehavior = .Pad

  if duration >= 3600 {
    formatter.allowedUnits = [.Hour, .Minute, .Second]
  } else {
    formatter.allowedUnits = [.Minute, .Second]
  }

  return formatter.stringFromTimeInterval(duration) ?? ""
}

So you have

print(format(12)) // 0:12
print(format(65)) // 1:05
print(format(1750)) // 29:10
print(format(3890)) // 1:04:50
print(format(45720)) // 12:42:00

Solution 6 - Iphone

Swift 4

DateComponentsFormatter().string(from: <# TimeInterval #>)

ex:

DateComponentsFormatter().string(from: 59.0)

Solution 7 - Iphone

NSTimeInterval ti = 3667;
double hours = floor(ti / 60 / 60);
double minutes = floor((ti - (hours * 60 * 60)) / 60);
double seconds = floor(ti - (hours * 60 * 60) - (minutes * 60));

Solution 8 - Iphone

To "extend" Matthias Bauch's suggestion, in Swift I would make this a computed property of NSTimeInterval:

extension NSTimeInterval {
  var stringValue: String {
    let interval = Int(self)
    let seconds = interval % 60
    let minutes = (interval / 60) % 60
    let hours = (interval / 3600)
    return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
  }
}

The advantage of this is it's attached to the NSTimeInterval type, not your view controller or wherever else you put that function. To use you'd go something like:

let timeInterval = NSDate().timeIntervalSinceDate(start)        
self.elapsedTimeLabel.text = timeInterval.stringValue

Solution 9 - Iphone

Based on answer by @onmyway133 here is the Swift 4 version:

func format(duration: TimeInterval) -> String {
	let formatter = DateComponentsFormatter()
	formatter.zeroFormattingBehavior = .pad
	
	if duration >= 3600 {
		formatter.allowedUnits = [.hour, .minute, .second];
	} else {
		formatter.allowedUnits = [.minute, .second];
	}
	
	return formatter.string(from: duration) ?? "";
}

Solution 10 - Iphone

straight from apple docs: in h file:

 @property(strong,nonatomic)NSDateComponentsFormatter *timerFormatter;

in m file

@synthesize timerFormatter;

- (void)viewDidLoad {
[super viewDidLoad];
NSDateComponentsFormatter *timerFormatter = [[NSDateComponentsFormatter alloc] init];
timerFormatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional; 
//10:59 Positional THIS ONE DOES NOT SEEM TO WORK iOS<9 WHEN <1Minute JUST SHOWS 01, 10m 59s Abbreviated, 10min 59sec Short, 10minutes 59seconds Full ...
timerFormatter.allowedUnits = NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
}

whereever you need to convert your NSTimeInterval timeInterval to hh:mm:ss string, do this:

NSString *txt=[timerFormatter stringFromTimeInterval:timeInterval];

Solution 11 - Iphone

I guess, the timer fraction should be ceiled out. As Matthias' code was creating that issue in seconds, I use the following slightly modified from that of Matthias

    - (NSString *)stringFromTimeInterval:(NSTimeInterval)interval {
        int ti = (int) ceil(interval);
        int seconds = ti % 60;
        int minutes = (ti / 60) % 60;
        int hours = (ti / 3600);
        return [NSString stringWithFormat:@"%02d:%02d:%02d",hours, minutes, seconds];
    }

Solution 12 - Iphone

Objective C version of onmyway133's answer

- (NSString*) formatTimeInterval:(NSTimeInterval) timeInterval {
    
    NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
    
    formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
    
    if (timeInterval > 3600) {
        formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    } else {
        formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
    }
    
    return [formatter stringFromTimeInterval:timeInterval];
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionfuzzygoatView Question on Stackoverflow
Solution 1 - IphoneMatthias BauchView Answer on Stackoverflow
Solution 2 - IphonejrcView Answer on Stackoverflow
Solution 3 - IphoneScott GardnerView Answer on Stackoverflow
Solution 4 - IphoneRoshitView Answer on Stackoverflow
Solution 5 - Iphoneonmyway133View Answer on Stackoverflow
Solution 6 - IphoneJakubView Answer on Stackoverflow
Solution 7 - IphoneJulian F. WeinertView Answer on Stackoverflow
Solution 8 - IphoneKenny WinkerView Answer on Stackoverflow
Solution 9 - IphoneVahid AmiriView Answer on Stackoverflow
Solution 10 - IphoneBoris GafurovView Answer on Stackoverflow
Solution 11 - IphoneMujtahid AkonView Answer on Stackoverflow
Solution 12 - IphoneFonixView Answer on Stackoverflow