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.