ios - Número de días entre dos NSDates
nsdate swift (16)
Esta pregunta ya tiene una respuesta aquí:
¿Cómo podría determinar el número de días entre dos valores de NSDate
(teniendo en cuenta el tiempo también)?
Los valores de NSDate
están en cualquier forma que [NSDate date]
.
Específicamente, cuando un usuario ingresa al estado inactivo en mi aplicación de iPhone, almaceno el siguiente valor:
exitDate = [NSDate date];
Y cuando vuelven a abrir la aplicación, obtengo la hora actual:
NSDate *now = [NSDate date];
Ahora me gustaría implementar lo siguiente:
-(int)numberOfDaysBetweenStartDate:exitDate andEndDate:now
¿Por qué no solo?
int days = [date1 timeIntervalSinceDate:date2]/24/60/60;
¿Por qué usar el siguiente método NSDate?
- (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate
¡Esto devolverá el número de segundos entre sus dos fechas y puede dividir por 86,400 para obtener el número de días!
¿Quiere decir días calendario o periodos de 24 horas? es decir, ¿es martes a las 9 p.m. un día antes del miércoles a las 6 a.m., o menos de un día?
Si te refieres a la primera, es un poco complicado y tendrás que recurrir a manipulaciones a través de NSCalendar
y NSDateComponent
que no recuerdo de ninguna manera.
Si se refiere a esto último, solo obtenga los intervalos de tiempo de las fechas desde la fecha de referencia, reste uno del otro y divida por 24 horas ( 24 * 60 * 60
) para obtener el intervalo aproximado, los segundos intercalares no incluidos.
@Brian
La respuesta de Brian es buena, solo calcula la diferencia en días en términos de trozos de 24 horas, pero no en las diferencias del día calendario. Por ejemplo, las 23:59 del 24 de diciembre están a solo 1 minuto del día de Navidad, a los efectos de muchas aplicaciones que aún se consideran un día. La función daysBetween de Brian devolvería 0.
Tomando prestado de la implementación original de Brian y del principio / final del día, utilizo lo siguiente en mi programa: ( NSDate al principio del día y al final del día )
- (NSDate *)beginningOfDay:(NSDate *)date
{
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
return [cal dateFromComponents:components];
}
- (NSDate *)endOfDay:(NSDate *)date
{
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
[components setHour:23];
[components setMinute:59];
[components setSecond:59];
return [cal dateFromComponents:components];
}
- (int)daysBetween:(NSDate *)date1 and:(NSDate *)date2 {
NSDate *beginningOfDate1 = [self beginningOfDay:date1];
NSDate *endOfDate1 = [self endOfDay:date1];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *beginningDayDiff = [calendar components:NSDayCalendarUnit fromDate:beginningOfDate1 toDate:date2 options:0];
NSDateComponents *endDayDiff = [calendar components:NSDayCalendarUnit fromDate:endOfDate1 toDate:date2 options:0];
if (beginningDayDiff.day > 0)
return beginningDayDiff.day;
else if (endDayDiff.day < 0)
return endDayDiff.day;
else {
return 0;
}
}
Aquí hay una implementación de la función de Brian en Swift:
class func daysBetweenThisDate(fromDateTime:NSDate, andThisDate toDateTime:NSDate)->Int?{
var fromDate:NSDate? = nil
var toDate:NSDate? = nil
let calendar = NSCalendar.currentCalendar()
calendar.rangeOfUnit(NSCalendarUnit.DayCalendarUnit, startDate: &fromDate, interval: nil, forDate: fromDateTime)
calendar.rangeOfUnit(NSCalendarUnit.DayCalendarUnit, startDate: &toDate, interval: nil, forDate: toDateTime)
if let from = fromDate {
if let to = toDate {
let difference = calendar.components(NSCalendarUnit.DayCalendarUnit, fromDate: from, toDate: to, options: NSCalendarOptions.allZeros)
return difference.day
}
}
return nil
}
Aquí hay una implementación que usé para determinar el número de días calendario entre dos fechas:
+ (NSInteger)daysBetweenDate:(NSDate*)fromDateTime andDate:(NSDate*)toDateTime
{
NSDate *fromDate;
NSDate *toDate;
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate
interval:NULL forDate:fromDateTime];
[calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate
interval:NULL forDate:toDateTime];
NSDateComponents *difference = [calendar components:NSCalendarUnitDay
fromDate:fromDate toDate:toDate options:0];
return [difference day];
}
EDITAR:
Fantástica solución anterior, aquí está la versión Swift a continuación como una extensión en NSDate
:
extension NSDate {
func numberOfDaysUntilDateTime(toDateTime: NSDate, inTimeZone timeZone: NSTimeZone? = nil) -> Int {
let calendar = NSCalendar.currentCalendar()
if let timeZone = timeZone {
calendar.timeZone = timeZone
}
var fromDate: NSDate?, toDate: NSDate?
calendar.rangeOfUnit(.Day, startDate: &fromDate, interval: nil, forDate: self)
calendar.rangeOfUnit(.Day, startDate: &toDate, interval: nil, forDate: toDateTime)
let difference = calendar.components(.Day, fromDate: fromDate!, toDate: toDate!, options: [])
return difference.day
}
}
Un poco de desenvolvimiento forzado que puede eliminar según su caso de uso.
La solución anterior también funciona para zonas horarias distintas de la zona horaria actual, perfectas para una aplicación que muestra información sobre lugares de todo el mundo.
Esta es la mejor solución que he encontrado. Parece utilizar el método aprobado por Apple para determinar cualquier cantidad de unidades entre NSDates.
- (int)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2 {
NSUInteger unitFlags = NSDayCalendarUnit;
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
return [components day]+1;
}
Por ejemplo, si también quieres meses, podrías incluir ''NSMonthCalendarUnit'' como un unitFlag.
Para acreditar al blogger original, encontré esta información aquí (aunque hubo un pequeño error que he reparado anteriormente): http://cocoamatic.blogspot.com/2010/09/nsdate-number-of-days-between-two-dates.html?showComment=1306198273659#c6501446329564880344
He publicado una clase / biblioteca de código abierto para hacer esto.
Eche un vistazo a RelativeDateDescriptor , que se puede usar para obtener la diferencia horaria de la siguiente manera ...
RelativeDateDescriptor *descriptor = [[RelativeDateDescriptor alloc] initWithPriorDateDescriptionFormat:@"%@ ago" postDateDescriptionFormat:@"in %@"];
// date1: 1st January 2000, 00:00:00
// date2: 6th January 2000, 00:00:00
[descriptor describeDate:date2 relativeTo:date1]; // Returns ''5 days ago''
[descriptor describeDate:date1 relativeTo:date2]; // Returns ''in 5 days''
La solución que encontré fue:
+(NSInteger)getDaysDifferenceBetween:(NSDate *)dateA and:(NSDate *)dateB {
if ([dateA isEqualToDate:dateB])
return 0;
NSCalendar * gregorian =
[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate * dateToRound = [dateA earlierDate:dateB];
int flags = (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit);
NSDateComponents * dateComponents =
[gregorian components:flags fromDate:dateToRound];
NSDate * roundedDate = [gregorian dateFromComponents:dateComponents];
NSDate * otherDate = (dateToRound == dateA) ? dateB : dateA ;
NSInteger diff = abs([roundedDate timeIntervalSinceDate:otherDate]);
NSInteger daysDifference = floor(diff/(24 * 60 * 60));
return daysDifference;
}
Aquí estoy efectivamente redondeando la primera fecha para comenzar desde el comienzo del día y luego calculando la diferencia como Jonathan sugiere arriba ...
Necesitaba la cantidad de días entre dos fechas, incluido el día de inicio. por ejemplo, los días entre el 14-2-2012 y el 16-2-2012 producirían un resultado de 3.
+ (NSInteger)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2 {
NSUInteger unitFlags = NSDayCalendarUnit;
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
NSInteger daysBetween = abs([components day]);
return daysBetween+1;
}
Tenga en cuenta que no importa en qué orden proporcione las fechas. Siempre devolverá un número positivo.
Otro enfoque:
NSDateFormatter* dayFmt = [[NSDateFormatter alloc] init];
[dayFmt setTimeZone:<whatever time zone you want>];
[dayFmt setDateFormat:@"g"];
NSInteger firstDay = [[dayFmt stringFromDate:firstDate] integerValue];
NSInteger secondDay = [[dayFmt stringFromDate:secondDate] integerValue];
NSInteger difference = secondDay - firstDay;
Tiene la ventaja sobre el esquema timeIntervalSince...
que se puede tener en cuenta la zona horaria, y no hay ambigüedad con intervalos de pocos segundos cortos o largos de un día.
Y un poco más compacto y menos confuso que los enfoques de NSDateComponents.
Simplemente agregue una respuesta para aquellos que visitan esta página tratando de hacer esto en Swift. El enfoque es más o menos el mismo.
private class func getDaysBetweenDates(startDate:NSDate, endDate:NSDate) -> NSInteger {
var gregorian: NSCalendar = NSCalendar.currentCalendar();
let flags = NSCalendarUnit.DayCalendarUnit
let components = gregorian.components(flags, fromDate: startDate, toDate: endDate, options: nil)
return components.day
}
Esta respuesta se encontró here , en la sección de discusión del siguiente método:
components(_:fromDate:toDate:options:)
Tengo uno, no estoy seguro de que sea exactamente lo que quiere, pero podría ayudar a algunos de ustedes, (¡me ayudó!)
Mi objetivo era saber si, entre dos fechas (menos de 24 horas de diferencia), tuve un día "de más de un día" + 1:
Hice lo siguiente (un poco arcaico, lo admito)
NSDate *startDate = ...
NSDate *endDate = ...
NSDate ya formateado por otro NSDateFormatter (este es solo para este propósito :)
NSDateFormatter *dayFormater = [[NSDateFormatter alloc]init];
[dayFormater setDateFormat:@"dd"];
int startDateDay = [[dayFormater stringFromDate:startDate]intValue];
int endDateDay = [[dayFormater stringFromDate:dateOn]intValue];
if (endDateDay > startDateDay) {
NSLog(@"day+1");
} else {
NSLog(@"same day");
}
tal vez algo como esto ya exista, pero no lo encontré
Tim
Yo uso esto como método de categoría para la clase NSDate
// returns number of days (absolute value) from another date (as number of midnights beween these dates)
- (int)daysFromDate:(NSDate *)pDate {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSInteger startDay=[calendar ordinalityOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitEra
forDate:[NSDate date]];
NSInteger endDay=[calendar ordinalityOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitEra
forDate:pDate];
return abs(endDay-startDay);
}
Actualización de Swift 3.0
extension Date {
func differenceInDaysWithDate(date: Date) -> Int {
let calendar = Calendar.current
let date1 = calendar.startOfDay(for: self)
let date2 = calendar.startOfDay(for: date)
let components = calendar.dateComponents([.day], from: date1, to: date2)
return components.day ?? 0
}
}
Actualización de Swift 2.0
extension NSDate {
func differenceInDaysWithDate(date: NSDate) -> Int {
let calendar: NSCalendar = NSCalendar.currentCalendar()
let date1 = calendar.startOfDayForDate(self)
let date2 = calendar.startOfDayForDate(date)
let components = calendar.components(.Day, fromDate: date1, toDate: date2, options: [])
return components.day
}
}
Solución Original
Otra solución en Swift.
Si su propósito es obtener el número exacto del día entre dos fechas, puede solucionar este problema de esta manera:
// Assuming that firstDate and secondDate are defined
// ...
var calendar: NSCalendar = NSCalendar.currentCalendar()
// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDayForDate(firstDate)
let date2 = calendar.startOfDayForDate(secondDate)
let flags = NSCalendarUnit.DayCalendarUnit
let components = calendar.components(flags, fromDate: date1, toDate: date2, options: nil)
components.day // This will return the number of day(s) between dates
NSDate *lastDate = [NSDate date];
NSDate *todaysDate = [NSDate date];
NSTimeInterval lastDiff = [lastDate timeIntervalSinceNow];
NSTimeInterval todaysDiff = [todaysDate timeIntervalSinceNow];
NSTimeInterval dateDiff = lastDiff - todaysDiff;
dateDiff será el número de segundos entre las dos fechas. Solo divida por la cantidad de segundos en un día.