Вопрос по nstimeinterval, time, cocoa, iphone – Как мне разбить NSTimeInterval на год, месяцы, дни, часы, минуты и секунды на iPhone?

55

У меня есть интервал времени, который охватывает годы, и я хочу, чтобы все компоненты времени от года до секунд.

Моя первая мысль - целочисленное деление временного интервала на секунды в году, вычитание его из текущего количества секунд, деление его на секунды в месяце, вычитание этого значения из промежуточного итога и так далее.

Это кажется просто запутанным, и я читал, что всякий раз, когда вы делаете что-то, что выглядит запутанным, возможно, существует встроенный метод.

Есть?

Я интегрировал второй метод Алекса в свой код.

Это в методе, вызванном UIDatePicker в моем интерфейсе.

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);

Когда я устанавливаю дату выбора на 1 год и 1 день в прошлом, я получаю:

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

что составляет 1 месяц и 16 часов. Если в прошлом я выбрал 1 день, я останусь на той же сумме.

Update: У меня есть приложение, которое вычисляет ваш возраст в годах, учитывая ваш день рождения (установленный из UIDatePicker), но оно часто было выключено. Это доказывает, что была неточность, но я не могу понять, откуда она, не так ли?

да, один месяц и шестнадцать часов выходных. willc2
Если вы выбрали дату в один день назад, вы отключились на один месяц и шестнадцать часов? Alex Reynolds
Если результат равен одному месяцу и шестнадцати часам вне зависимости от того, какое значение вы выберете, либо вы вычтите это из переменных со сдвигом, либо вам нужно оценить, откуда происходит эта ошибка. Я предполагаю, что с вашим интервалом что-то не так, если вы всегда отключены на эту сумму. Alex Reynolds

Ваш Ответ

9   ответов
3

Это работает для меня:

    float *lenghInSeconds = 2345.234513;
    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:lenghInSeconds];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];


    [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];

    [formatter setDateFormat:@"HH:mm:ss"];
    NSLog(@"%@", [formatter stringFromDate:date]); 
    [formatter release];

Основное отличие здесь заключается в том, что вам нужно настроить часовой пояс.

-1 из-за того, что забыть что-либо за 24 часа не получится
+1 за не забывающий часовой пояс
5

С iOS8 и выше вы можете использоватьNSDateComponentsFormatter

У этого есть методы, чтобы преобразовать разницу во времени в удобной отформатированной строке.

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

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

Это дает вывод - 2 недели, 4 дня, 18 часов, 57 минут, 32 секунды

2
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.
...
0
- (NSString *)convertTimeFromSeconds:(NSString *)seconds {

    // Return variable.
    NSString *result = @"";

    // Int variables for calculation.
    int secs = [seconds intValue];
    int tempHour    = 0;
    int tempMinute  = 0;
    int tempSecond  = 0;

    NSString *hour      = @"";
    NSString *minute    = @"";
    NSString *second    = @"";

    // Convert the seconds to hours, minutes and seconds.
    tempHour    = secs / 3600;
    tempMinute  = secs / 60 - tempHour * 60;
    tempSecond  = secs - (tempHour * 3600 + tempMinute * 60);

    hour    = [[NSNumber numberWithInt:tempHour] stringValue];
    minute  = [[NSNumber numberWithInt:tempMinute] stringValue];
    second  = [[NSNumber numberWithInt:tempSecond] stringValue];

    // Make time look like 00:00:00 and not 0:0:0
    if (tempHour < 10) {
        hour = [@"0" stringByAppendingString:hour];
    } 

    if (tempMinute < 10) {
        minute = [@"0" stringByAppendingString:minute];
    }

    if (tempSecond < 10) {
        second = [@"0" stringByAppendingString:second];
    }

    if (tempHour == 0) {

        NSLog(@"Result of Time Conversion: %@:%@", minute, second);
        result = [NSString stringWithFormat:@"%@:%@", minute, second];

    } else {

        NSLog(@"Result of Time Conversion: %@:%@:%@", hour, minute, second); 
        result = [NSString stringWithFormat:@"%@:%@:%@",hour, minute, second];

    }

    return result;

}
0

Вот еще одна возможность, несколько более чистая:

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;
Это звучит как ошибка.
Для интервала времени 1 секунда (одна секунда назад) возвращается «год -1, месяц 12, день 31, час 16, минута 0, секунда 1». willc2
16

Этот код учитывает время перехода на летнее время и другие возможные неприятности.

NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorianCalendar components: (NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit )
                                                    fromDate:startDate
                                                      toDate:[NSDate date]
                                                     options:0];


NSLog(@"%ld", [components year]);
NSLog(@"%ld", [components month]);
NSLog(@"%ld", [components day]);
NSLog(@"%ld", [components hour]);
NSLog(@"%ld", [components minute]);
NSLog(@"%ld", [components second]);
100

Brief Description

Just another approach to complete the answer of JBRWilkinson but adding some code. It can also offers a solution to Alex Reynolds's comment.

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).

Create 2 NSDate whose difference is the NSTimeInterval you want to break down. (If your NSTimeInterval comes from comparing 2 NSDate you don't need to do this step, and you don't even need the NSTimeInterval, just apply the dates to the NSCalendar method).

Get your quotes from NSDateComponents

Sample Code

// The time interval 
NSTimeInterval theTimeInterval = ...;

// 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
NSCalendarUnit unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;

NSDateComponents *breakdownInfo = [sysCalendar components:unitFlags fromDate:date1  toDate:date2  options:0];
NSLog(@"Break down: %i min : %i hours : %i days : %i months", [breakdownInfo minute], [breakdownInfo hour], [breakdownInfo day], [breakdownInfo month]);
Спасибо, сэр.
NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit не рекомендуется в IOS8, используйтеNSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitDay | NSCalendarUnitMonth вместо
Превосходный ответ .. !!! Большое спасибо!!!!!!!! (Y),
Фактический рабочий код, в отличие от текста, приветствуется. willc2
у этого метода есть проблема с переходом на летнее время, вы столкнетесь с проблемой 1 часа напрямую.
3

Или есть мой метод класса. Он не обрабатывает годы, но его можно легко добавить, хотя он лучше подходит для небольших временных интервалов, таких как дни, часы и минуты. Он учитывает множественное число и показывает только то, что нужно:

+(NSString *)TimeRemainingUntilDate:(NSDate *)date {

    NSTimeInterval interval = [date timeIntervalSinceNow];
    NSString * timeRemaining = nil;

    if (interval > 0) {

        div_t d = div(interval, 86400);
        int day = d.quot;
        div_t h = div(d.rem, 3600);
        int hour = h.quot;
        div_t m = div(h.rem, 60);
        int min = m.quot;

        NSString * nbday = nil;
        if(day > 1)
            nbday = @"days";
        else if(day == 1)
            nbday = @"day";
        else
            nbday = @"";
        NSString * nbhour = nil;
        if(hour > 1)
            nbhour = @"hours";
        else if (hour == 1)
            nbhour = @"hour";
        else
            nbhour = @"";
        NSString * nbmin = nil;
        if(min > 1)
            nbmin = @"mins";
        else
            nbmin = @"min";

        timeRemaining = [NSString stringWithFormat:@"%@%@ %@%@ %@%@",day ? [NSNumber numberWithInt:day] : @"",nbday,hour ? [NSNumber numberWithInt:hour] : @"",nbhour,min ? [NSNumber numberWithInt:min] : @"00",nbmin];
    }
    else
        timeRemaining = @"Over";

    return timeRemaining;
}
4

Преобразовать ваш интервал вNSDate с помощью+dateWithIntervalSince1970, получить компоненты даты из этого, используяNSCalendar& APOS; s-componentsFromDate метод.

SDK Ссылка

+1. Чтобы быть немного более подробным для OP, вы не можете точно преобразовать временной интервал в эти компоненты, вы должны знать, откуда вы начинаете (то есть тогда dateWithIntervalFrom1970), потому что, например, 29 дней - это месяц, если вы находитесь в феврале 1-е (за исключением двухлетних лет, конечно), но не в том случае, если вы 1-го января ...

Похожие вопросы