Как мне разбить NSTimeInterval на год, месяцы, дни, часы, минуты и секунды на iPhone?

StackOverflow https://stackoverflow.com/questions/1237778

Вопрос

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

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

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

Есть ли?

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

Это в методе, вызываемом 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 год 1 месяц 1 день 16 часов 0 минуты 20 секунд

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

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

Это было полезно?

Решение

Краткое описание

  1. Просто еще один подход для завершения ответа JBRWilkinson, но с добавлением некоторого кода.Он также может предложить решение по комментарию Алекса Рейнольдса.

  2. Используйте метод NSCalendar:

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

    • "Возвращает в качестве объекта NSDateComponents, использующего указанные компоненты, разницу между двумя предоставленными датами".(Из документации API).

  3. Создайте 2 NSDate, разница между которыми заключается в NSTimeInterval, который вы хотите разбить.(Если ваш NSTimeInterval получен в результате сравнения 2 NSDate, вам не нужно выполнять этот шаг, и вам даже не нужен NSTimeInterval, просто примените даты к методу NSCalendar).

  4. Получите ваши котировки из NSDateComponents

Пример кода

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

Другие советы

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

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

Преобразуйте свой интервал в NSDate используя +dateWithIntervalSince1970, извлеките компоненты даты из этого , используя NSCalendar's -componentsFromDate способ.

Ссылка на SDK

Начиная с iOS8 и выше, вы можете использовать NSDateComponentsFormatter

В нем есть методы для преобразования разницы во времени в удобную для пользователя форматированную строку.

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

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

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

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

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

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

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

+(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;
}
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.
...
- (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;

}

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

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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top