Comment comparer deux NSDates: lequel est le plus récent?

244

J'essaie de réaliser une synchronisation dropBox et j'ai besoin de comparer les dates de deux fichiers. L'un est sur mon compte dropBox et l'autre sur mon iPhone.

J'ai trouvé ce qui suit, mais j'obtiens des résultats inattendus. Je suppose que je fais quelque chose de fondamentalement mauvais en comparant les deux dates. J'ai simplement utilisé les opérateurs> <, mais je suppose que ce n'est pas bon car je compare deux chaînes NSDate. Et c'est parti:

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

Cela m'a donné la sortie (aléatoire et erronée) suivante:

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.

ou celui-ci qui se trouve être correct:

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.
ça ne fait rien
la source
11
Doublons: 1 2 3 4 5 6 & c.
jscs
1
@JoshCaswell si c'est un vrai doublon, pourquoi ne pas les fusionner? Vous l'avez déjà fait ...
Dan Rosenstark
1
Seuls les modérateurs diamant peuvent effectuer une fusion, @Yar.
jscs

Réponses:

658

Supposons deux dates:

NSDate *date1;
NSDate *date2;

Ensuite, la comparaison suivante indiquera ce qui est le plus tôt / le plus tard / le même:

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

Veuillez vous référer à la documentation de la classe NSDate pour plus de détails.

Nick Weaver
la source
Charmant! Beats déconner avec [date1 plus tôtDate: date2] etc ... Merci - pour une raison que je n'avais jamais pensé à comparer: avant.
SomaMan
11
J'aime compter sur le fait que NSOrderedAscending <0 et NSOrderedDescending> 0. Cela rend la comparaison plus facile à lire: [date1 compare: date2] <0 / * date1 <date2 * / et évite l'erreur (facile à faire) @albertamg souligné. ;-)
jpap
Eh bien - la méthode de comparaison est aussi sujette aux erreurs que les erreurs ponctuelles. Ainsi, vous devez utiliser (NSDate *) laterDate: (NSDate *) anotherDate qui renverra la date ultérieure des deux. vous n'avez qu'à comparer votre résultat attendu et vous avez terminé! Pas de tripotage avec "Waaait descendant / ascendant?!"
masi
@jpap Cela m'a aussi dérangé; il semble qu'Apple veuille que vous considériez le résultat comme date1 -> date2croissant / décroissant (et donc date1 est plus tard ou plus tôt respectivement).
Ja͢ck
@Jack c'est une manière plus abstraite sans nombres magiques (-1,0,1) pour les algorithmes de tri pour mettre les éléments en ordre. Vous pouvez également redéfinir ces constantes vous-même avec un nom plus lisible. Ma réponse fait le travail mais n'est pas lauréate du code lisible. Faites défiler vers le bas, il y en a d'autres bons.
Nick Weaver
50

Tard dans la soirée, mais un autre moyen simple de comparer les objets NSDate est de les convertir en types primitifs, ce qui permet une utilisation facile de '>' '<' '==' etc.

par exemple.

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

timeIntervalSinceReferenceDateconvertit la date en secondes depuis la date de référence (1er janvier 2001, GMT). Comme timeIntervalSinceReferenceDaterenvoie un NSTimeInterval (qui est un double typedef), nous pouvons utiliser des comparateurs primitifs.

Alors au-dessus
la source
4
Un peu plus intuitif que (NSComparisonResult)compare:(NSDate *)mais encore assez bavard pour cette opération simple ... (comme d'habitude)
Pierre de LESPINAY
1
peut aussi faire[dateA timeIntervalSinceDate:dateB] > 0
Scott Fister
14

Dans Swift, vous pouvez surcharger les opérateurs existants:

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

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

Ensuite, vous pouvez comparer NSDates directement avec <, >et ==(déjà pris en charge).

Andrew
la source
Si j'essaye d'en faire une extension, j'obtiens "Les opérateurs ne sont autorisés qu'à portée globale", des suggestions?
JohnVanDijk
@JohnVanDijk vous ne pouvez pas le mettre dans une extension. Je le mettrais dans le même fichier que l'extension, mais en dehors de{ ... }
Andrew
13

NSDate a une fonction de comparaison.

compare:Renvoie une NSComparisonResultvaleur qui indique l'ordre temporel du récepteur et une autre date donnée.

(NSComparisonResult)compare:(NSDate *)anotherDate

Paramètres : anotherDate date à laquelle comparer le récepteur. Cette valeur ne doit pas être nulle. Si la valeur est nulle, le comportement n'est pas défini et peut changer dans les futures versions de Mac OS X.

Valeur de retour:

  • Si le récepteur et anotherDate sont exactement égaux, NSOrderedSame
  • Si le destinataire arrive plus tard qu'une autre date, NSOrderedDescending
  • Si le récepteur est plus tôt dans le temps que anotherDate, NSOrderedAscending.
Gary
la source
@Irene existe-t-il un moyen de comparer deux objets NSDate dans lesquels seule la composante temporelle est différente? Pour une raison quelconque, la méthode ci-dessus ne fonctionne pas.
UsEFuL
12

Vous souhaitez utiliser les méthodes NSDate compare :, laterDate :, earlyDate :, ou isEqualToDate :. Utiliser les opérateurs <et> dans cette situation, c'est comparer les pointeurs, pas les dates

Dan F
la source
11
- (NSDate *)earlierDate:(NSDate *)anotherDate

Cela renvoie la première du récepteur et une autreDate. Si les deux sont identiques, le récepteur est retourné.

Maulik
la source
1
Notez que l'objet de sauvegarde de NSDates peut être optimisé sur les versions 64 bits de votre code compilé de sorte que les dates qui représentent la même heure auront la même adresse. Ainsi, si cDate = [aDate earlierDate:bDate]alors cDate == aDateet cDate == bDatepeut être vrai à la fois. J'ai trouvé cela en train de travailler sur iOS 8.
Ben Flynn
1
Inversement, sur les plateformes 32 bits, si les dates ne sont pas identiques, -earlierDate:(et -laterDate:) ne peuvent renvoyer ni le récepteur ni l'argument.
Ben Lings
7

Certains utilitaires de date, y compris les comparaisons EN ANGLAIS, ce qui est bien:

#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

La mise en oeuvre:

#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
la source
1
Ou utilisez simplement: github.com/erica/NSDate-Extensions
Dan Rosenstark
6

Tu devrais utiliser :

- (NSComparisonResult)compare:(NSDate *)anotherDate

pour comparer les dates. Il n'y a pas de surcharge d'opérateur dans l'objectif C.

Joris Mans
la source
6

Pourquoi n'utilisez-vous pas ces NSDateméthodes de comparaison:

- (NSDate *)earlierDate:(NSDate *)anotherDate;
- (NSDate *)laterDate:(NSDate *)anotherDate;
justicepenny
la source
4

J'ai rencontré presque la même situation, mais dans mon cas, je vérifie si la différence de nombre de jours

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 lorsque vous devez comparer NSDate en jours / mois / année

Andy
la source
NSDayCalendarUnit est obsolète, utilisez plutôt NSCalendarUnitDay
Mazen Kasser
2

Vous pouvez également comparer deux dates par cette méthode

        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
la source
0

Je l'ai essayé j'espère que ça marche pour vous

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];
Inforoute Concept
la source
0

Utilisez cette fonction simple pour comparer les dates

-(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
la source