How do I break down an NSTimeInterval into year, months, days, hours, minutes and seconds on iPhone?

Viewed 48645

I have a time interval that spans years and I want all the time components from year down to seconds.

My first thought is to integer divide the time interval by seconds in a year, subtract that from a running total of seconds, divide that by seconds in a month, subtract that from the running total and so on.

That just seems convoluted and I've read that whenever you are doing something that looks convoluted, there is probably a built-in method.

Is there?

I integrated Alex's 2nd method into my code.

It's in a method called by a UIDatePicker in my interface.

NSDate *now = [NSDate date];
NSDate *then = self.datePicker.date;
NSTimeInterval howLong = [now timeIntervalSinceDate:then];

NSDate *date = [NSDate dateWithTimeIntervalSince1970:howLong];
NSString *dateStr = [date description];
const char *dateStrPtr = [dateStr UTF8String];
int year, month, day, hour, minute, sec;

sscanf(dateStrPtr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &sec);
year -= 1970;

NSLog(@"%d years\n%d months\n%d days\n%d hours\n%d minutes\n%d seconds", year, month, day, hour, minute, sec);

When I set the date picker to a date 1 year and 1 day in the past, I get:

1 years 1 months 1 days 16 hours 0 minutes 20 seconds

which is 1 month and 16 hours off. If I set the date picker to 1 day in the past, I am off by the same amount.

Update: I have an app that calculates your age in years, given your birthday (set from a UIDatePicker), yet it was often off. This proves there was an inaccuracy, but I can't figure out where it comes from, can you?

9 Answers

From iOS8 and above you can use NSDateComponentsFormatter

It has methods to convert time difference in user friendly formatted string.

NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleFull;

NSLog(@"%@", [formatter stringFromTimeInterval:1623452]);

This gives the output - 2 weeks, 4 days, 18 hours, 57 minutes, 32 seconds

Convert your interval into an NSDate using +dateWithIntervalSince1970, get the date components out of that using NSCalendar's -componentsFromDate method.

SDK Reference

NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];

// format: YYYY-MM-DD HH:MM:SS ±HHMM
NSString *dateStr = [date description];
NSRange range;

// year
range.location = 0;
range.length = 4;
NSString *yearStr = [dateStr substringWithRange:range];
int year = [yearStr intValue] - 1970;

// month
range.location = 5;
range.length = 2;
NSString *monthStr = [dateStr substringWithRange:range];
int month = [monthStr intValue];

// day, etc.
...

Here's another possibility, somewhat cleaner:

NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSString *dateStr = [date description];
const char *dateStrPtr = [dateStr UTF8String];

// format: YYYY-MM-DD HH:MM:SS ±HHMM
int year, month, day, hour, minutes, seconds;
sscanf(dateStrPtr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minutes, &seconds);
year -= 1970;
Related