Como faço para quebrar um NSTimeInterval em anos, meses, dias, horas, minutos e segundos no iPhone?

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

Pergunta

Eu tenho um intervalo de tempo que se estende por anos e eu quero que todos os componentes de tempo do ano até segundos.

Meu primeiro pensamento é a divisão inteira o intervalo de tempo de segundos em um ano, subtrair que a partir de um total de execução de segundos, divida que por segundos em um mês, subtrair que a partir do total de execução e assim por diante.

que apenas parece complicado e eu li que sempre que você está fazendo algo que parece complicado, provavelmente há um built-in método.

Existe?

I integrado segundo o método de Alex em meu código.

Está em um método chamado por um UIDatePicker na minha 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);

Quando eu definir o selecionador de data para uma data de 1 ano e 1 dia no passado, eu recebo:

1 ano 1 meses 1 dias e 16 horas 0 minutos e 20 segundos

que é de 1 mês e 16 horas de folga. Se eu definir o selecionador de data para um dia no passado, estou fora pela mesma quantidade.

Atualizar : Eu tenho um aplicativo que calcula a sua idade em anos, dado o seu aniversário (conjunto de uma UIDatePicker), mas foi muitas vezes fora. Isto prova que havia uma imprecisão, mas eu não consigo descobrir de onde vem, não é?

Foi útil?

Solução

Breve Descrição

  1. Apenas uma outra abordagem para completar a resposta de JBRWilkinson mas a adição de algum código. Pode também oferece uma solução para o comentário de Alex Reynolds.

  2. Use o método NSCalendar:

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

    • "Retorna, como um NSDateComponents objeto usando componentes especificados, a diferença entre duas datas fornecidas". (A partir da documentação da API).

  3. Criar 2 NSDate cuja diferença é o NSTimeInterval você quer quebrar. (Se o seu NSTimeInterval vem comparando 2 NSDate você não precisa fazer esse passo, e você não precisa mesmo do NSTimeInterval, basta aplicar as datas para o método NSCalendar).

  4. Obter suas citações de NSDateComponents

Exemplo de código

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

Outras dicas

Este código está ciente do dia economizando tempo e outras coisas desagradáveis ??possíveis luz.

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

Converter o intervalo em um NSDate usando +dateWithIntervalSince1970, obter os componentes de data para fora do método NSCalendar que o uso de -componentsFromDate.

SDK Referência

De iOS8 e acima você pode usar NSDateComponentsFormatter

Tem métodos para converter diferença de tempo em usuário string formatada amigável.

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

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

Isto dá a saída - 2 semanas, 4 dias, 18 horas, 57 minutos, 32 segundos

Isso funciona para mim:

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

A principal diferença aqui é que você precisa para ajustar o fuso horário.

Ou não é o meu método de classe. Ele não lida com anos, mas que poderia facilmente ser addedn que é melhor para pequenas timelaps como dias, horas e minutos. É ter plurais em conta e só mostra o que é necessário:

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

}

Aqui está uma outra possibilidade, um pouco mais limpo:

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;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top