Confronto di due NSDate e ignorando il componente temporale

Qual è il modo più efficiente / consigliato di confrontare due NSDate? Mi piacerebbe essere in grado di vedere se entrambe le date sono nello stesso giorno, indipendentemente dal tempo e ho iniziato a scrivere un codice che usa il valore timeIntervalSinceDate: method all’interno della class NSDate e ottiene il numero intero di questo valore diviso per il numero di secondi in un giorno. Questo sembra lungo e mi sento come se mi mancasse qualcosa di ovvio.

Il codice che sto cercando di risolvere è:

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

dove key e todaysDate sono oggetti NSDate e oggi la creazione di date è la seguente:

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

Saluti

Dave

Impostare l’ora nella data su 00:00:00 prima di eseguire il confronto:

 unsigned int flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay; NSCalendar* calendar = [NSCalendar currentCalendar]; NSDateComponents* components = [calendar components:flags fromDate:date]; NSDate* dateOnly = [calendar dateFromComponents:components]; // ... necessary cleanup 

Quindi puoi confrontare i valori della data. Vedi la panoramica nella documentazione di riferimento .

Sono sorpreso che nessun’altra risposta abbia questa opzione per ottenere la data di “inizio del giorno” per gli oggetti:

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

Che imposta date1 e date2 all’inizio dei rispettivi giorni. Se sono uguali, sono nello stesso giorno.

O questa opzione:

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

Che imposta day1 e day1 su valori un po ‘arbitrari che possono essere confrontati. Se sono uguali, sono nello stesso giorno.

C’è un nuovo metodo che è stato introdotto in NSCalendar con iOS 8 che rende questo molto più semplice.

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

Imposta la granularità alle unità che contano. Ciò ignora tutte le altre unità e limita il confronto a quelle selezionate.

Per iOS8 e versioni successive, controllare se due date si verificano nello stesso giorno è semplice come:

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

Vedi la documentazione

Questa è una scorciatoia di tutte le risposte:

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

Ho usato l’approccio di Duncan C, ho corretto alcuni errori che ha fatto

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

Io uso questo piccolo metodo di utilizzo:

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

(Ovviamente devi avere un ivar chiamato calendar_ contenente un NSCalendar .)

Usando questo, è facile verificare se una data è oggi come questa:

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

( [NSDate date] restituisce la data e l’ora correnti.)

Questo è ovviamente molto simile a quello che suggerisce Gregory. Lo svantaggio di questo approccio è che tende a creare molti oggetti temporanei NSDate . Se si elaborano molte date, si consiglia di utilizzare un altro metodo, ad esempio confrontare i componenti direttamente o lavorare con oggetti NSDateComponents anziché NSDates .

La risposta è più semplice di quanto tutti lo dimostrino. NSCalendar ha un metodo

 components:fromDate:toDate:options 

Questo metodo ti consente di calcolare la differenza tra due date utilizzando qualsiasi unità desideri.

Quindi scrivi un metodo come questo:

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

Se il metodo sopra riportato restituisce zero, le due date sono nello stesso giorno.

Da iOS 8.0 in poi, puoi utilizzare:

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

Se il risultato è, ad esempio, NSOrderedDescending, otherDate è precedente alla data [Data NSDate] in termini di giorni.

Non vedo questo metodo nella documentazione NSCalendar ma è nelle differenze API iOS 7.1 a iOS 8.0

Per gli sviluppatori che codificano in Swift 3

 if(NSCalendar.current.isDate(selectedDate, inSameDayAs: NSDate() as Date)){ // Do something } 
 int interval = (int)[firstTime timeIntervalSinceDate:secondTime]/(60*60*24); if (interval!=0){ //not the same day; } 

la mia soluzione era di due conversioni 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 } 

Con Swift 3, in base alle tue esigenze, puoi scegliere uno dei due seguenti modelli per risolvere il tuo problema.


# 1. Utilizzo del metodo di compare(_:to:toGranularity:)

Calendar ha un metodo chiamato compare(_:​to:​to​Granularity:​) . compare(_:​to:​to​Granularity:​) ha la seguente dichiarazione:

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

Confronta le date date fino al componente dato, segnalandole ordered​Same se sono uguali nel componente dato e tutti i componenti più grandi, altrimenti o ordered​Ascending in ordered​Ascending o ordered​Descending .

Il codice Playground qui sotto è molto caldo per usarlo:

 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. Uso di dateComponents(_:from:to:)

Calendar ha un metodo chiamato dateComponents(_:from:to:) . dateComponents(_:from:to:) ha la seguente dichiarazione:

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

Restituisce la differenza tra due date.

Il codice Playground qui sotto è molto caldo per usarlo:

 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 } 

La documentazione relativa a NSDate indica che il compare: e isEqual: metodi eseguiranno entrambi un confronto di base e isEqual: i risultati, sebbene continuino a farcela nel tempo.

Probabilmente il modo più semplice per gestire l’attività sarebbe creare un nuovo metodo isToday con l’effetto di quanto segue:

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

Questo è un gatto particolarmente brutto, ma ecco un altro modo per farlo. Non dico che sia elegante, ma probabilmente è il più vicino ansible con il supporto data / ora in 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)]; 

confronta ora anche per risolvere la differenza di 1 giorno