¿Cómo puedo romper a un NSTimeInterval en años, meses, días, horas, minutos y segundos en el iPhone?
-
11-09-2019 - |
Pregunta
Tengo un intervalo de tiempo que se extiende por años y quiero que todos los componentes de tiempo de años hasta segundos.
Lo primero que pensé es a entero dividir el intervalo de tiempo por segundo en un año, restar que a partir de un total acumulado de segundos, divida que por segundo en un mes, restar que a partir de la ejecución total y así sucesivamente.
Eso sólo parece complicado y he leído que cada vez que usted está haciendo algo que parece complicado, es probable que haya un método integrado.
¿Hay?
integré segundo método de Alex en mi código.
Está en un método llamado por un UIDatePicker en mi interfaz.
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);
Cuando me puse el selector de fecha para una fecha de 1 año y 1 día en el pasado, me sale:
1 año 1 meses 1 días 16 horas 0 minutos 20 segundos
, que es de 1 mes y 16 horas de descanso. Si fijo el selector de fechas 1 día en el pasado, estoy fuera por la misma cantidad.
Actualizar : Tengo una aplicación que calcula su edad en años, dada su cumpleaños (conjunto de una UIDatePicker), sin embargo, a menudo estaba fuera. Esto demuestra que había algún error, pero no puedo averiguar de dónde viene, ¿verdad?
Solución
Breve descripción
-
Sólo otro enfoque para completar la respuesta de JBRWilkinson pero añadiendo algún código. También se ofrece una solución a los comentarios de Alex Reynolds.
-
Método de Uso NSCalendar:
-
(NSDateComponents *)components:(NSUInteger)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSUInteger)opts
-
"devoluciones, como un NSDateComponents objeto utilizando componentes especificados, la diferencia entre dos fechas suministrados". (A partir de la documentación de la API).
-
-
Crea 2 NSDate cuya diferencia es la NSTimeInterval desea romper. (Si su NSTimeInterval proviene de la comparación de 2 NSDate que no es necesario realizar este paso, y usted ni siquiera necesita el NSTimeInterval, solo se aplica a las fechas el método NSCalendar).
-
Obtener sus citas de NSDateComponents
Código de ejemplo
// 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]);
Otros consejos
Este código es consciente de los tiempos de ahorro de luz del día y otras cosas desagradables posibles.
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]);
Convertir el intervalo en un NSDate
usando +dateWithIntervalSince1970
, obtener los componentes de la fecha de método NSCalendar
que el uso de -componentsFromDate
.
De iOS8 y arriba se puede utilizar NSDateComponentsFormatter
Tiene métodos para convertir diferencia de tiempo en la cadena con formato de usuario amigable.
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleFull;
NSLog(@"%@", [formatter stringFromTimeInterval:1623452]);
Esto da la salida - 2 semanas, 4 días, 18 horas, 57 minutos, 32 segundos
Esto funciona para mí:
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];
La diferencia principal aquí es que usted necesita para ajustar la zona horaria.
O no es mi método de clase. No maneja años, pero que podría ser fácilmente addedn pesar de que es mejor para los pequeños como timelaps días, horas y minutos. Se toma en cuenta los plurales y sólo muestra lo que se necesita:
+(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;
}
Aquí hay otra posibilidad, un poco más limpio:
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;