How to convert an NSTimeInterval (seconds) into minutes

Solution 1:

Brief Description

  1. The answer from Brian Ramsay is more convenient if you only want to convert to minutes.
  2. If you want Cocoa API do it for you and convert your NSTimeInterval not only to minutes but also to days, months, week, etc,... I think this is a more generic approach
  3. Use NSCalendar method:

    • (NSDateComponents *)components:(NSUInteger)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSUInteger)opts

    • "Returns, as an NSDateComponents object using specified components, the difference between two supplied dates". From the API documentation.

  4. Create 2 NSDate whose difference is the NSTimeInterval you want to convert. (If your NSTimeInterval comes from comparing 2 NSDate you don't need to do this step, and you don't even need the NSTimeInterval).

  5. Get your quotes from NSDateComponents

Sample Code

// The time interval 
NSTimeInterval theTimeInterval = 326.4;

// Get the system calendar
NSCalendar *sysCalendar = [NSCalendar currentCalendar];

// Create the NSDates
NSDate *date1 = [[NSDate alloc] init];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:theTimeInterval sinceDate:date1]; 

// Get conversion to months, days, hours, minutes
unsigned int unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;

NSDateComponents *conversionInfo = [sysCalendar components:unitFlags fromDate:date1  toDate:date2  options:0];

NSLog(@"Conversion: %dmin %dhours %ddays %dmoths",[conversionInfo minute], [conversionInfo hour], [conversionInfo day], [conversionInfo month]);

[date1 release];
[date2 release];

Known issues

  • Too much for just a conversion, you are right, but that's how the API works.
  • My suggestion: if you get used to manage your time data using NSDate and NSCalendar, the API will do the hard work for you.

Solution 2:

pseudo-code:

minutes = floor(326.4/60)
seconds = round(326.4 - minutes * 60)

Solution 3:

All of these look more complicated than they need to be! Here is a short and sweet way to convert a time interval into hours, minutes and seconds:

NSTimeInterval timeInterval = 326.4;
long seconds = lroundf(timeInterval); // Since modulo operator (%) below needs int or long

int hour = seconds / 3600;
int mins = (seconds % 3600) / 60;
int secs = seconds % 60;

Note when you put a float into an int, you get floor() automatically, but you can add it to the first two if if makes you feel better :-)

Solution 4:

Forgive me for being a Stack virgin... I'm not sure how to reply to Brian Ramsay's answer...

Using round will not work for second values between 59.5 and 59.99999. The second value will be 60 during this period. Use trunc instead...

 double progress;

 int minutes = floor(progress/60);
 int seconds = trunc(progress - minutes * 60);

Solution 5:

If you're targeting at or above iOS 8 or OS X 10.10, this just got a lot easier. The new NSDateComponentsFormatter class allows you to convert a given NSTimeInterval from its value in seconds to a localized string to show the user. For example:

Objective-C

NSTimeInterval interval = 326.4;

NSDateComponentsFormatter *componentFormatter = [[NSDateComponentsFormatter alloc] init];

componentFormatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
componentFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropAll;

NSString *formattedString = [componentFormatter stringFromTimeInterval:interval];
NSLog(@"%@",formattedString); // 5:26

Swift

let interval = 326.4

let componentFormatter = NSDateComponentsFormatter()

componentFormatter.unitsStyle = .Positional
componentFormatter.zeroFormattingBehavior = .DropAll

if let formattedString = componentFormatter.stringFromTimeInterval(interval) {
    print(formattedString) // 5:26
}

NSDateCompnentsFormatter also allows for this output to be in longer forms. More info can be found in NSHipster's NSFormatter article. And depending on what classes you're already working with (if not NSTimeInterval), it may be more convenient to pass the formatter an instance of NSDateComponents, or two NSDate objects, which can be done as well via the following methods.

Objective-C

NSString *formattedString = [componentFormatter stringFromDate:<#(NSDate *)#> toDate:<#(NSDate *)#>];
NSString *formattedString = [componentFormatter stringFromDateComponents:<#(NSDateComponents *)#>];

Swift

if let formattedString = componentFormatter.stringFromDate(<#T##startDate: NSDate##NSDate#>, toDate: <#T##NSDate#>) {
    // ...
}

if let formattedString = componentFormatter.stringFromDateComponents(<#T##components: NSDateComponents##NSDateComponents#>) {
    // ...
}