CocoaDev

Edit AllPages

Hey there, I’ve written this method that changes an NSTimeInterval into a human readable NSString. It all works fine and dandy until we try to use it on a NSTimeInterval of a negative value.

Does anyone know of a solution?

Code: - (NSString )secondsToHumanReadableString:(NSTimeInterval)interval { // Due to the inaccuracy of the below constants once you get into scales of // years (something this small tool should never go) time tends to go “faster” // it isn’t actually going faster it just seems that way due to rounding errors. static const double second = 1; static const double minute = second * 60; static const double hour = minute * 60; static const double day = hour * 12; static const double month = day * 30.5; // 30.5 is the average and we don’t need to be *THAT precise. static const double year = day * 365; // Years aren’t exactly 365 either but it is more precise then ^month * 12.

NSTimeInterval workInterval = interval;

double years = 0;
double months = 0;
double days = 0;
double hours = 0;
double minutes = 0;
double seconds = 0;

// Year.
years = floor(workInterval / year);
workInterval -= year * years;

months = floor(workInterval / month);
workInterval -= month * months;

days = floor(workInterval / day);
workInterval -= day * days;

hours = floor(workInterval / hour);
workInterval -= hour * hours;

minutes = floor(workInterval / minute);
workInterval -= minute * minutes;

seconds = floor(workInterval);

NSMutableString * str = [[[NSMutableString alloc] init] autorelease];

if (years == 1) {
	[str appendString:[NSString stringWithFormat:@"%.0lf year ",years]];
}
else if (years != 0) {
	[str appendString:[NSString stringWithFormat:@"%.0lf years ",years]];
}

if (months == 1) {
	[str appendString:[NSString stringWithFormat:@"%.0lf month ",months]];
}
else if (months != 0) {
	[str appendString:[NSString stringWithFormat:@"%.0lf months ",months]];
}

if (days == 1) {
	[str appendString:[NSString stringWithFormat:@"%.0lf day ",days]];
}
else if (days != 0) {
	[str appendString:[NSString stringWithFormat:@"%.0lf days ",days]];
}

if (hours == 1) {
	[str appendString:[NSString stringWithFormat:@"%.0lf hour ",hours]];
}
else if (hours != 0) {
	[str appendString:[NSString stringWithFormat:@"%.0lf hours ",hours]];
}

if (minutes == 1) {
	[str appendString:[NSString stringWithFormat:@"%.0lf minute ",minutes]];
}
else if (minutes != 0) {
	[str appendString:[NSString stringWithFormat:@"%.0lf minutes ",minutes]];
}

if (seconds == 1) {
	[str appendString:[NSString stringWithFormat:@"%.0lf second ",seconds]];
}
else if (seconds != 0) {
	[str appendString:[NSString stringWithFormat:@"%.0lf seconds ",seconds]];
}

if ([str isEqualToString:@""]) [str setString:@"0 seconds "];
return str; }----

Looks pretty nice. You can solve your negative problem by checking for negative at the beginning, possibly adding a string or flag, and then inverting the value. Something like:

if(workInterval < 0.0) { [str appendString:@”Negative “]; workInterval = -workInterval; }

On a style/efficiency point, you can replace all of your lines that have [str appendString:[NSString stringWithFormat:…]] with the simpler and less wasteful [str appendFormat:…].


(extremely minor nitpick) You might also want to change the name of the method to -stringForTimeInterval: to match Cocoa’s… (I’d place it into a category of NSString, personally, and make it a class method).


You should check out NSCalendarDate. There are some methods that provide string descriptions of time intervals based on a user format. You have to create an NSCalendarDate object first from a time interval, but the rest is in the docs. –zootbobbalu


Thanks for the solutions all :-). I agree the name of the method wasn’t the best (hell it annoyed me as well!) but it was 3am…..


I created a version of this which mimics the time_ago_in_words helper from rails.

#import “NSString+TimeInterval.h”

#import

@implementation NSString (TimeInterval)

@end


Of course, you’d want to be able to localize that…


One more thing - day has 24 hours, not 12 ,)


For negative intervals, how about appending ‘ago’ ?