Come confrontare due NSDate: qual è la più recente?


244

Sto cercando di ottenere una sincronizzazione dropBox e devo confrontare le date di due file. Uno è sul mio account dropBox e uno è sul mio iPhone.

Ho pensato a quanto segue, ma ho ottenuto risultati inaspettati. Immagino che sto facendo qualcosa di fondamentalmente sbagliato quando si confrontano le due date. Ho semplicemente usato gli operatori> <, ma suppongo che non vada bene in quanto sto confrontando due stringhe NSDate. Eccoci qui:

NSLog(@"dB...lastModified: %@", dbObject.lastModifiedDate); 
NSLog(@"iP...lastModified: %@", [self getDateOfLocalFile:@"NoteBook.txt"]);

if ([dbObject lastModifiedDate] < [self getDateOfLocalFile:@"NoteBook.txt"]) {
    NSLog(@"...db is more up-to-date. Download in progress...");
    [self DBdownload:@"NoteBook.txt"];
    NSLog(@"Download complete.");
} else {
    NSLog(@"...iP is more up-to-date. Upload in progress...");
    [self DBupload:@"NoteBook.txt"];
    NSLog(@"Upload complete.");
}

Questo mi ha dato il seguente output (casuale e sbagliato):

2011-05-11 14:20:54.413 NotePage[6918:207] dB...lastModified: 2011-05-11 13:18:25 +0000
2011-05-11 14:20:54.414 NotePage[6918:207] iP...lastModified: 2011-05-11 13:20:48 +0000
2011-05-11 14:20:54.415 NotePage[6918:207] ...db is more up-to-date.

o questo che sembra essere corretto:

2011-05-11 14:20:25.097 NotePage[6903:207] dB...lastModified: 2011-05-11 13:18:25 +0000
2011-05-11 14:20:25.098 NotePage[6903:207] iP...lastModified: 2011-05-11 13:19:45 +0000
2011-05-11 14:20:25.099 NotePage[6903:207] ...iP is more up-to-date.

11
Duplicati: 1 2 3 4 5 6 e c.
— jscs,

1
@JoshCaswell se è un vero duplicato, perché non unirli? L'hai già fatto ...
— Dan Rosenstark,

1
Solo i moderatori di diamanti possono eseguire un'unione, @Yar.
— jscs,

Risposte:


658

Supponiamo che due date:

NSDate *date1;
NSDate *date2;

Quindi il seguente confronto dirà quale è precedente / successivo / stesso:

if ([date1 compare:date2] == NSOrderedDescending) {
    NSLog(@"date1 is later than date2");
} else if ([date1 compare:date2] == NSOrderedAscending) {
    NSLog(@"date1 is earlier than date2");
} else {
    NSLog(@"dates are the same");
}

Per ulteriori dettagli, consultare la documentazione della classe NSDate .


Bello! Batte in giro con [date1 precedenti Data: date2] ecc ... Grazie - per qualche ragione non avevo mai pensato di usare compare: prima.
— SomaMan,

11
Mi piace fare affidamento sul fatto che NSOrderedAscending <0 e NSOrderedDescending> 0. Questo rende il confronto più facile da leggere: [date1 compare: date2] <0 / * date1 <date2 * / ed evita l'errore (facile da fare) @albertamg sottolineato. ;-)
— jpap

Bene - il metodo di confronto è soggetto a errori come errori off-by-one. Pertanto, è necessario utilizzare (NSDate *) laterDate: (NSDate *) anotherDate che restituirà la data successiva di entrambi. quindi devi solo confrontare il risultato atteso e il gioco è fatto! Non giocherellare con "Waaait decrescente / crescente?!"
— masi,

@jpap Anche quello mi ha incasinato; sembra che Apple voglia che tu pensi al risultato come date1 -> date2crescente / decrescente (e quindi la data1 è rispettivamente successiva o precedente).
— Ja͢ck,

@Jack è un modo più astratto senza numeri magici (-1,0,1) per gli algoritmi di ordinamento per mettere in ordine gli elementi. Puoi anche ridefinire quelle costanti con un nome più leggibile. La mia risposta è fare il lavoro ma non è il vincitore del codice leggibile. Scorri verso il basso, ce ne sono altri buoni.
— Nick Weaver,

50

In ritardo per la festa, ma un altro modo semplice per confrontare gli oggetti NSDate è convertirli in tipi primitivi che consentono un facile utilizzo di '>' '<' '==' ecc

per esempio.

if ([dateA timeIntervalSinceReferenceDate] > [dateB timeIntervalSinceReferenceDate]) {
    //do stuff
}

timeIntervalSinceReferenceDateconverte la data in secondi dalla data di riferimento (1 gennaio 2001, GMT). Poiché timeIntervalSinceReferenceDaterestituisce un NSTimeInterval (che è un doppio typedef), possiamo usare comparatori primitivi.


4
Leggermente più intuitivo di (NSComparisonResult)compare:(NSDate *)ma ancora abbastanza prolisso per questa semplice operazione ... (come al solito)
— Pierre de LESPINAY

1
può anche fare[dateA timeIntervalSinceDate:dateB] > 0
— Scott Fister il

14

In Swift, puoi sovraccaricare gli operatori esistenti:

func > (lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.timeIntervalSinceReferenceDate > rhs.timeIntervalSinceReferenceDate
}

func < (lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.timeIntervalSinceReferenceDate < rhs.timeIntervalSinceReferenceDate
}

Quindi, è possibile confrontare direttamente con NSDates <, >e ==(già supportato).


Se provo a farne un'estensione, ottengo "Gli operatori sono ammessi solo nell'ambito globale", suggerimenti?
— JohnVanDijk,

@JohnVanDijk non puoi inserirlo in un'estensione. Lo metterei nello stesso file dell'estensione, ma al di fuori del{ ... }
— Andrew

13

NSDate ha una funzione di confronto.

compare:Restituisce un NSComparisonResultvalore che indica l'ordinamento temporale del destinatario e un'altra data specificata.

(NSComparisonResult)compare:(NSDate *)anotherDate

Parametri : anotherDate la data con cui confrontare il ricevitore. Questo valore non deve essere nullo. Se il valore è zero, il comportamento non è definito e potrebbe cambiare nelle versioni future di Mac OS X.

Valore di ritorno:

  • Se il destinatario e un altroData sono esattamente uguali tra loro, NSOrderedSame
  • Se il ricevitore è più tardi di un altroData, NSOrderedDescending
  • Se il ricevitore è precedente nel tempo di anotherDate, NSOrderedAscending.

@Irene c'è un modo per confrontare due oggetti NSDate in cui solo il componente time è diverso? Per qualche ragione il metodo sopra non funziona.
— Utente

12

Si desidera utilizzare i metodi di confronto NSDate :, laterDate :, precedentiDate: oppure isEqualToDate:. L'uso degli operatori <e> in questa situazione sta confrontando i puntatori, non le date


11
- (NSDate *)earlierDate:(NSDate *)anotherDate

Ciò restituisce il precedente del ricevitore e un altroData. Se entrambi sono uguali, viene restituito il ricevitore.


1
Si noti che l'oggetto di backup di NSDates può essere ottimizzato su versioni a 64 bit del codice compilato in modo tale che le date che rappresentano la stessa ora avranno lo stesso indirizzo. Quindi se cDate = [aDate earlierDate:bDate]allora cDate == aDatee cDate == bDateentrambi possono essere veri. Ho trovato questo facendo un po 'di lavoro su iOS 8.
— Ben Flynn l'

1
Al contrario, su piattaforme a 32 bit, se le date non sono le stesse, -earlierDate:(e -laterDate:) non possono restituire né il destinatario né l'argomento.
— Ben Lings,

7

Alcuni programmi di utilità per la data, inclusi i confronti IN INGLESE, il che è carino:

#import <Foundation/Foundation.h>


@interface NSDate (Util)

-(BOOL) isLaterThanOrEqualTo:(NSDate*)date;
-(BOOL) isEarlierThanOrEqualTo:(NSDate*)date;
-(BOOL) isLaterThan:(NSDate*)date;
-(BOOL) isEarlierThan:(NSDate*)date;
- (NSDate*) dateByAddingDays:(int)days;

@end

L'implemento:

#import "NSDate+Util.h"


@implementation NSDate (Util)

-(BOOL) isLaterThanOrEqualTo:(NSDate*)date {
    return !([self compare:date] == NSOrderedAscending);
}

-(BOOL) isEarlierThanOrEqualTo:(NSDate*)date {
    return !([self compare:date] == NSOrderedDescending);
}
-(BOOL) isLaterThan:(NSDate*)date {
    return ([self compare:date] == NSOrderedDescending);

}
-(BOOL) isEarlierThan:(NSDate*)date {
    return ([self compare:date] == NSOrderedAscending);
}

- (NSDate *) dateByAddingDays:(int)days {
    NSDate *retVal;
    NSDateComponents *components = [[NSDateComponents alloc] init];
    [components setDay:days];

    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    retVal = [gregorian dateByAddingComponents:components toDate:self options:0];
    return retVal;
}

@end

1
O semplicemente usa: github.com/erica/NSDate-Extensions
— Dan Rosenstark


6

Dovresti usare :

- (NSComparisonResult)compare:(NSDate *)anotherDate

per confrontare le date. Non c'è sovraccarico dell'operatore nell'obiettivo C.


6

Perché non usate questi NSDatemetodi di confronto:

- (NSDate *)earlierDate:(NSDate *)anotherDate;
- (NSDate *)laterDate:(NSDate *)anotherDate;

4

Ho riscontrato quasi la stessa situazione, ma nel mio caso sto controllando se il numero di giorni differisce

NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *compDate = [cal components:NSDayCalendarUnit fromDate:fDate toDate:tDate options:0];
int numbersOfDaysDiff = [compDate day]+1; // do what ever comparison logic with this int.

Utile quando è necessario confrontare NSDate in unità Giorni / Mese / Anno


NSDayCalendarUnit è obsoleto, quindi usa NSCalendarUnitDay invece
— Mazen Kasser

2

Puoi confrontare due date anche con questo metodo

        switch ([currenttimestr  compare:endtimestr])
        {
            case NSOrderedAscending:

                // dateOne is earlier in time than dateTwo
                break;

            case NSOrderedSame:

                // The dates are the same
                break;
            case NSOrderedDescending:

                // dateOne is later in time than dateTwo


                break;

        }

0

L'ho provato, spero che funzioni per te

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];      
int unitFlags =NSDayCalendarUnit;      
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];     
NSDate *myDate; //= [[NSDate alloc] init];     
[dateFormatter setDateFormat:@"dd-MM-yyyy"];   
myDate = [dateFormatter dateFromString:self.strPrevioisDate];     
NSDateComponents *comps = [gregorian components:unitFlags fromDate:myDate toDate:[NSDate date] options:0];   
NSInteger day=[comps day];

0

Utilizzare questa semplice funzione per il confronto delle date

-(BOOL)dateComparision:(NSDate*)date1 andDate2:(NSDate*)date2{

BOOL isTokonValid;

if ([date1 compare:date2] == NSOrderedDescending) {
    NSLog(@"date1 is later than date2");
    isTokonValid = YES;
} else if ([date1 compare:date2] == NSOrderedAscending) {
    NSLog(@"date1 is earlier than date2");
    isTokonValid = NO;
} else {
    isTokonValid = NO;
    NSLog(@"dates are the same");
}

return isTokonValid;}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.