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.
compare(_:to:toGranularity:)
Calendar
ha un metodo chiamato compare(_:to:toGranularity:)
. compare(_:to:toGranularity:)
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
orderedSame
se sono uguali nel componente dato e tutti i componenti più grandi, altrimenti oorderedAscending
inorderedAscending
oorderedDescending
.
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" }
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