Pregunta

¿Cuál es la forma más eficiente / recomendada de la comparación de dos NSDates? Me gustaría ser capaz de ver si ambas fechas están en el mismo día, con independencia del tiempo y he empezado a escribir algo de código que utiliza el timeIntervalSinceDate: método dentro de la clase NSDate y obtiene el número entero de este valor dividido por el número de segundos en un día. Esto parece largo aliento y me siento como que estoy perdiendo algo obvio.

El código que estoy tratando de arreglar es:

if (!([key compare:todaysDate] == NSOrderedDescending))
{
    todaysDateSection = [eventSectionsArray count] - 1;
}

donde clave y todaysDate son objetos NSDate y todaysDate está creando usando:

NSDate *todaysDate = [[NSDate alloc] init];

Regards

David

¿Fue útil?

Solución

Se establece el tiempo en el día a 00:00:00 antes de hacer la comparación:

unsigned int flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
NSCalendar* calendar = [NSCalendar currentCalendar];

NSDateComponents* components = [calendar components:flags fromDate:date];

NSDate* dateOnly = [calendar dateFromComponents:components];

// ... necessary cleanup

A continuación, puede comparar los valores de fecha. Vea Introducción a la en la documentación de referencia .

Otros consejos

Me sorprende que no hay otras respuestas tienen esta opción para conseguir el "principio del día" fecha de los objetos:

[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay startDate:&date1 interval:NULL forDate:date1];
[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay startDate:&date2 interval:NULL forDate:date2];

¿Qué establece date1 y date2 al inicio de sus respectivas días. Si son iguales, que están en el mismo día.

O esta opción:

NSUInteger day1 = [[NSCalendar currentCalendar] ordinalityOfUnit:NSDayCalendarUnit inUnit: forDate:date1];
NSUInteger day2 = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:date2];

que establece day1 y day2 a valores algo arbitrarias que se pueden comparar. Si son iguales, que están en el mismo día.

Hay un método nuevo que se introdujo a NSCalendar con iOS 8 que hace esto mucho más fácil.

- (NSComparisonResult)compareDate:(NSDate *)date1 toDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit NS_AVAILABLE(10_9, 8_0);

Se establece la granularidad de la unidad (s) que la materia. Esto no tiene en cuenta todas las demás unidades y limita la comparación a los seleccionados.

Para iOS8 y después, comprobar si dos fechas se producen en el mismo día es tan simple como:

[[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2]

Consulte documentación

Esta es una forma rápida de todas las respuestas:

NSInteger interval = [[[NSCalendar currentCalendar] components: NSDayCalendarUnit
                                                                  fromDate: date1
                                                                    toDate: date2
                                                                   options: 0] day];
    if(interval<0){
       //date1<date2
    }else if (interval>0){
       //date2<date1
    }else{
       //date1=date2
    }

He utilizado el enfoque de Duncan C, he corregido algunos errores que cometió

-(NSInteger) daysBetweenDate:(NSDate *)firstDate andDate:(NSDate *)secondDate { 

    NSCalendar *currentCalendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [currentCalendar components: NSDayCalendarUnit fromDate: firstDate toDate: secondDate options: 0];

    NSInteger days = [components day];

    return days;
}

Yo uso este método poco util:

-(NSDate*)normalizedDateWithDate:(NSDate*)date
{
   NSDateComponents* components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
                                              fromDate: date];
   return [calendar_ dateFromComponents:components]; // NB calendar_ must be initialized
}

(Naturalmente, también necesita tener una llamada Ivar calendar_ que contiene un NSCalendar.)

El uso de este, es fácil comprobar si una fecha es hoy en día como esto:

[[self normalizeDate:aDate] isEqualToDate:[self normalizeDate:[NSDate date]]];

([NSDate date] devuelve la fecha y hora actuales.)

Esto es por supuesto muy similar a lo que sugiere Gregory. El inconveniente de este método es que tiende a crear un montón de objetos NSDate temporales. Si usted va a procesar una gran cantidad de fechas, yo recomendaría usar algún otro método, como la comparación de los componentes directamente, o trabajar con objetos en lugar de NSDateComponents NSDates.

La respuesta es más simple que todo el mundo hace que fuera a ser. NSCalendar tiene un método

components:fromDate:toDate:options

Este método permite calcular la diferencia entre dos fechas utilizando cualquier unidad que desea.

Así que escribir un método como este:

-(NSInteger) daysBetweenDate: (NSDate *firstDate) andDate: (NSDate *secondDate)
{
  NSCalendar *currentCalendar = [NSCalendar currentCalendar];
  NSDateComponents components* = [currentCalendar components: NSDayCalendarUnit
    fromDate: firstDate 
    toDate: secondDate
    options: 0];

  NSInteger days = [components days];
  return days;
}

Si el método anterior devuelve cero, las dos fechas están en el mismo día.

A partir de iOS 8.0 en adelante, puede utilizar:

NSCalendar *calendar = [NSCalendar currentCalendar];
NSComparisonResult dateComparison = [calendar compareDate:[NSDate date] toDate:otherNSDate toUnitGranularity:NSCalendarUnitDay];

Si el resultado es, por ejemplo, NSOrderedDescending, otherDate es antes del [fecha NSDate] en términos de días.

No veo este método en la documentación NSCalendar pero es en el iOS 7.1 a iOS 8.0 diferencias API

Para los desarrolladores de codificación en Swift 3

if(NSCalendar.current.isDate(selectedDate, inSameDayAs: NSDate() as Date)){
     // Do something
}

Con Swift 3, de acuerdo con sus necesidades, puede elegir uno de los dos modelos siguientes con el fin de resolver su problema.


# 1. Utilizando el método compare(_:to:toGranularity:)

Calendar tiene un método llamado compare(_:​to:​to​Granularity:​) . compare(_:​to:​to​Granularity:​) tiene la siguiente declaración:

func compare(_ date1: Date, to date2: Date, toGranularity component: Calendar.Component) -> ComparisonResult
  

compara las fechas dadas hasta el componente dado, informar de ellos ordered​Same si son los mismos en el componente dado y todos los componentes de mayor tamaño, por lo demás, ya sea ordered​Ascending o ordered​Descending.

El código Zona de juegos muestra caliente utilizarlo:

import Foundation

let calendar = Calendar.current
let date1 = Date() // "Mar 31, 2017, 2:01 PM"
let date2 = calendar.date(byAdding: .day, value: -1, to: date1)! // "Mar 30, 2017, 2:01 PM"
let date3 = calendar.date(byAdding: .hour, value: 1, to: date1)! // "Mar 31, 2017, 3:01 PM"

/* Compare date1 and date2 */
do {
    let comparisonResult = calendar.compare(date1, to: date2, toGranularity: .day)
    switch comparisonResult {
    case ComparisonResult.orderedSame:
        print("Same day")
    default:
        print("Not the same day")
    }
    // Prints: "Not the same day"
}

/* Compare date1 and date3 */
do {
    let comparisonResult = calendar.compare(date1, to: date3, toGranularity: .day)
    if case ComparisonResult.orderedSame = comparisonResult {
        print("Same day")
    } else {
        print("Not the same day")
    }
    // Prints: "Same day"
}

# 2. Usando dateComponents(_:from:to:)

Calendar tiene un método llamado dateComponents(_:from:to:) . dateComponents(_:from:to:) tiene la siguiente declaración:

func dateComponents(_ components: Set<Calendar.Component>, from start: Date, to end: Date) -> DateComponents
  

Devuelve la diferencia entre dos fechas.

El código Zona de juegos muestra caliente utilizarlo:

import Foundation

let calendar = Calendar.current
let date1 = Date() // "Mar 31, 2017, 2:01 PM"
let date2 = calendar.date(byAdding: .day, value: -1, to: date1)! // "Mar 30, 2017, 2:01 PM"
let date3 = calendar.date(byAdding: .hour, value: 1, to: date1)! // "Mar 31, 2017, 3:01 PM"

/* Compare date1 and date2 */
do {
    let dateComponents = calendar.dateComponents([.day], from: date1, to: date2)
    switch dateComponents.day {
    case let value? where value < 0:
        print("date2 is before date1")
    case let value? where value > 0:
        print("date2 is after date1")
    case let value? where value == 0:
        print("date2 equals date1")
    default:
        print("Could not compare dates")
    }
    // Prints: date2 is before date1
}

/* Compare date1 and date3 */
do {
    let dateComponents = calendar.dateComponents([.day], from: date1, to: date3)
    switch dateComponents.day {
    case let value? where value < 0:
        print("date2 is before date1")
    case let value? where value > 0:
        print("date2 is after date1")
    case let value? where value == 0:
        print("date2 equals date1")
    default:
        print("Could not compare dates")
    }
    // Prints: date2 equals date1
}
int interval = (int)[firstTime timeIntervalSinceDate:secondTime]/(60*60*24);
if (interval!=0){
   //not the same day;
}

mi solución era dos conversiones con NSDateFormatter:

    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"yyyyMMdd"];
    [dateFormat setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];

    NSDate *today = [NSDate dateWithTimeIntervalSinceNow:0];
    NSString *todayString=[dateFormat stringFromDate:today];
    NSDate *todayWithoutHour=[dateFormat dateFromString:todayString];

    if ([today compare:exprDate] == NSOrderedDescending)
    {
       //do  
    }

La documentación relativa NSDate indica que los métodos compare: y isEqual: serán tanto realizar una comparación básica y ordenar los resultados, aunque todavía factor en el tiempo.

Probablemente la forma más sencilla de gestionar la tarea sería la creación de un nuevo método isToday al efecto de los siguientes:

- (bool)isToday:(NSDate *)otherDate
{
    currentTime = [however current time is retrieved]; // Pardon the bit of pseudo-code

    if (currentTime < [otherDate timeIntervalSinceNow])
    {
        return YES;
    }
    else
    {
        return NO;
    }
}

Este es un gato particularmente desagradable a la piel, pero aquí hay otra manera de hacerlo. No digo que es elegante, pero es probablemente lo más cerca que se puede llegar con la ayuda de fecha / hora en IOS.

bool isToday = [[NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterNoStyle] isEqualToString:[NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterNoStyle]];
NSUInteger unit = NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit;
NSDateComponents *comp = [cal components:unit
                                fromDate:nowDate
                                  toDate:setDate
                                 options:0];

NSString *dMonth;
dMonth = [NSString stringWithFormat:@"%02ld",comp.month];
NSString *dDay;
dDay = [NSString stringWithFormat:@"%02ld",comp.day + (comp.hour > 0 ? 1 : 0)];

comparar horas, así fijar diferencia 1 día

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top