So vergleichen Sie zwei NSDates: Welches ist neuer?

244

Ich versuche eine DropBox-Synchronisierung zu erreichen und muss die Daten zweier Dateien vergleichen. Eine befindet sich auf meinem DropBox-Konto und eine auf meinem iPhone.

Ich habe mir Folgendes ausgedacht, aber ich erhalte unerwartete Ergebnisse. Ich denke, ich mache etwas grundlegend Falsches, wenn ich die beiden Daten vergleiche. Ich habe einfach die Operatoren> <verwendet, aber ich denke, das ist nicht gut, da ich zwei NSDate-Zeichenfolgen vergleiche. Auf geht's:

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.");
}

Dies gab mir die folgende (zufällige & falsche) Ausgabe:

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.

oder dieser, der zufällig richtig ist:

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.
keine Ursache
quelle
11
Duplikate: 1 2 3 4 5 6 & c.
Jscs
1
@JoshCaswell Wenn es sich um ein echtes Duplikat handelt, warum nicht zusammenführen? Du hast es schon mal gemacht ...
Dan Rosenstark
1
Nur Diamantmoderatoren können eine Zusammenführung durchführen, @Yar.
Jscs

Antworten:

658

Nehmen wir zwei Daten an:

NSDate *date1;
NSDate *date2;

Der folgende Vergleich zeigt dann, was früher / später / gleich ist:

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");
}

Weitere Informationen finden Sie in der Dokumentation zur NSDate-Klasse .

Nick Weaver
quelle
Schön! Beats spielen mit [Datum1 früherDatum: Datum2] usw. ... Danke - aus irgendeinem Grund hätte ich nie gedacht, Vergleiche zu verwenden: vorher.
SomaMan
11
Ich verlasse mich gerne auf die Tatsache, dass NSOrderedAscending <0 und NSOrderedDescending> 0 sind. Dies erleichtert das Lesen des Vergleichs: [date1 compare: date2] <0 / * date1 <date2 * / und vermeidet den (leicht zu machenden) Fehler @albertamg wies darauf hin. ;-)
jpap
Nun - die Vergleichsmethode ist genauso fehleranfällig wie einzelne Fehler. Daher sollten Sie (NSDate *) laterDate verwenden: (NSDate *) anotherDate, das das spätere Datum von beiden zurückgibt. Sie vergleichen also einfach Ihr erwartetes Ergebnis und sind fertig! Kein Herumspielen mit "Waaait absteigend / aufsteigend ?!"
Masi
@jpap Das hat mich auch durcheinander gebracht; Es scheint, dass Apple möchte, dass Sie das Ergebnis als date1 -> date2aufsteigend / absteigend betrachten (und daher ist Datum1 später bzw. früher).
Ja͢ck
@Jack Es ist eine abstraktere Methode ohne magische Zahlen (-1,0,1), um Algorithmen zu sortieren, um Elemente in Ordnung zu bringen. Sie können diese Konstanten auch selbst mit einem besser lesbaren Namen neu definieren. Meine Antwort macht den Job, ist aber nicht der Preisträger von lesbarem Code. Scrollen Sie nach unten, es gibt noch andere gute.
Nick Weaver
50

Spät zur Party, aber eine andere einfache Möglichkeit, NSDate-Objekte zu vergleichen, besteht darin, sie in primitive Typen umzuwandeln, was die einfache Verwendung von '>' '<' '==' usw. Ermöglicht

z.B.

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

timeIntervalSinceReferenceDatekonvertiert das Datum in Sekunden seit dem Referenzdatum (1. Januar 2001, GMT). Da timeIntervalSinceReferenceDateein NSTimeInterval (ein doppeltes typedef) zurückgegeben wird, können wir primitive Komparatoren verwenden.

Also drüber hinweg
quelle
4
Etwas intuitiver als, (NSComparisonResult)compare:(NSDate *)aber dennoch ziemlich ausführlich für diese einfache Operation ... (wie üblich)
Pierre de LESPINAY
1
kann auch tun[dateA timeIntervalSinceDate:dateB] > 0
Scott Fister
14

In Swift können Sie vorhandene Operatoren überladen:

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

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

Dann können Sie NSDates direkt mit vergleichen <, >und ==(bereits unterstützt).

Andrew
quelle
Wenn ich versuche, eine Erweiterung daraus zu machen, erhalte ich "Operatoren sind nur im globalen Bereich zulässig", Vorschläge?
JohnVanDijk
@ JohnVanDijk Sie können es nicht in eine Erweiterung einfügen. Ich würde es in die gleiche Datei wie die Erweiterung legen, aber außerhalb der{ ... }
Andrew
13

NSDate hat eine Vergleichsfunktion.

compare:Gibt einen NSComparisonResultWert zurück, der die zeitliche Reihenfolge des Empfängers und ein anderes angegebenes Datum angibt.

(NSComparisonResult)compare:(NSDate *)anotherDate

Parameter : anotherDate Das Datum, mit dem der Empfänger verglichen werden soll. Dieser Wert darf nicht Null sein. Wenn der Wert Null ist, ist das Verhalten undefiniert und kann sich in zukünftigen Versionen von Mac OS X ändern.

Rückgabewert:

  • Wenn der Empfänger und ein anderes Datum genau gleich sind, NSOrderedSame
  • Wenn der Empfänger später als ein anderes Datum ist, NSOrderedDescending
  • Wenn der Empfänger früher als ein anderes Datum ist , NSOrderedAscending.
Gary
quelle
@Irene Gibt es eine Möglichkeit, zwei NSDate-Objekte zu vergleichen, bei denen nur die Zeitkomponente unterschiedlich ist? Aus irgendeinem Grund funktioniert die obige Methode nicht.
USA
12

Sie möchten die Methoden NSDate compare:, laterDate:, previousDate: oder isEqualToDate: verwenden. Wenn Sie in dieser Situation die Operatoren <und> verwenden, werden die Zeiger und nicht die Daten verglichen

Dan F.
quelle
11
- (NSDate *)earlierDate:(NSDate *)anotherDate

Dies gibt das frühere des Empfängers und ein anderes Datum zurück. Wenn beide gleich sind, wird der Empfänger zurückgegeben.

Maulik
quelle
1
Beachten Sie, dass das Sicherungsobjekt von NSDates möglicherweise für 64-Bit-Versionen Ihres kompilierten Codes optimiert ist, sodass Daten, die dieselbe Zeit darstellen, dieselbe Adresse haben. Also wenn cDate = [aDate earlierDate:bDate]dann cDate == aDateund cDate == bDatekann beides wahr sein. Fand dies bei einigen Datumsarbeiten auf iOS 8.
Ben Flynn
1
Umgekehrt können -earlierDate:(und -laterDate:) auf 32-Bit-Plattformen, wenn die Daten nicht identisch sind, weder den Empfänger noch das Argument zurückgeben.
Ben Lings
7

Einige Datums-Dienstprogramme, einschließlich Vergleiche auf Englisch, was sehr schön ist:

#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

Die Umsetzung:

#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
Dan Rosenstark
quelle
1
Oder verwenden Sie einfach: github.com/erica/NSDate-Extensions
Dan Rosenstark
6

Du solltest benutzen :

- (NSComparisonResult)compare:(NSDate *)anotherDate

Daten vergleichen. In Ziel C gibt es keine Überlastung des Bedieners.

Joris Mans
quelle
6

Warum benutzt ihr nicht diese NSDateVergleichsmethoden:

- (NSDate *)earlierDate:(NSDate *)anotherDate;
- (NSDate *)laterDate:(NSDate *)anotherDate;
Gerechtigkeitspfennig
quelle
4

Ich habe fast die gleiche Situation erlebt, aber in meinem Fall überprüfe ich, ob sich die Anzahl der Tage unterscheidet

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.

Nützlich, wenn Sie NSDate in der Einheit Tage / Monat / Jahr vergleichen müssen

Andy
quelle
NSDayCalendarUnit ist veraltet, verwenden Sie stattdessen NSCalendarUnitDay
Mazen Kasser
2

Mit dieser Methode können Sie auch zwei Daten vergleichen

        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;

        }
kapil
quelle
0

Ich habe es versucht, hoffe es funktioniert für Sie

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];
Konzept Infoway
quelle
0

Verwenden Sie diese einfache Funktion zum Datumsvergleich

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