web-dev-qa-db-fra.com

Cocoa-Touch: Comment puis-je voir si deux NSDates sont dans la même journée?

J'ai besoin de savoir si deux instances NSDate proviennent toutes deux du même jour.

Existe-t-il un moyen plus facile/meilleur de le faire que d'obtenir les NSDateComponents et de comparer le jour/mois/année?

67
Prody

NSDateComponents sonne comme le meilleur pari pour moi. Une autre tactique à essayer consiste à le connecter sans frais à un CFDate, puis à utiliser CFDateGetAbsoluteTime et à effectuer une soustraction pour obtenir le temps entre les deux dates. Vous devrez cependant faire quelques calculs supplémentaires pour déterminer si le décalage horaire arrive les dates le même jour.

7
fbrereto

Si vous ciblez iOS 8 (et OS X 10.9) ou une version ultérieure , alors réponse de Joe est une meilleure solution en utilisant une nouvelle dans NSCalendar juste à cet effet:

-[NSCalendar isDate:inSameDayAsDate:]

Pour iOS 7 ou version antérieure : NSDateComponents est ma préférence. Que diriez-vous quelque chose comme ça:

- (BOOL)isSameDayWithDate1:(NSDate*)date1 date2:(NSDate*)date2 {
    NSCalendar* calendar = [NSCalendar currentCalendar];

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
    NSDateComponents* comp1 = [calendar components:unitFlags fromDate:date1];
    NSDateComponents* comp2 = [calendar components:unitFlags fromDate:date2];

    return [comp1 day]   == [comp2 day] &&
           [comp1 month] == [comp2 month] &&
           [comp1 year]  == [comp2 year];
}
154
progrmr

Si vous travaillez avec iOS 8, vous pouvez utiliser -isDate:inSameDayAsDate:.

De NSCalendar.h:

/*
    This API compares the Days of the given dates, reporting them equal if they are in the same Day.
*/
- (BOOL)isDate:(NSDate *)date1 inSameDayAsDate:(NSDate *)date2 NS_AVAILABLE(10_9, 8_0);

Notez que pour une raison quelconque, cela n'a pas été présenté dans la documentation officielle sur le site des développeurs d'Apple. Mais cela fait définitivement partie de l'API publique.

53
Joe Masilotti

(Remarque: regardez la réponse de Joe pour un bon moyen de le faire sur iOS 8+)

J'utilise juste un formateur de date:

NSDateFormatter *dateComparisonFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateComparisonFormatter setDateFormat:@"yyyy-MM-dd"];

if( [[dateComparisonFormatter stringFromDate:firstDate] isEqualToString:[dateComparisonFormatter stringFromDate:secondDate]] ) {
    …
}

HTH.

24
Ben Lachman

Dans Swift:

NSCalendar.currentCalendar().isDate(yourDate, equalToDate: yourOtherDate, toUnitGranularity: .Day)

Cela reviendra vrai s'ils sont le même jour.

13
vikzilla

J'aime la solution de progrmr, mais j'irais encore plus loin et ferais une catégorie de NSDate qui fournit cette méthode. Cela rendra votre code légèrement plus lisible, et vous n'aurez pas besoin de copier et coller la méthode dans chaque nouvelle classe qui pourrait en avoir besoin - il suffit d'importer le fichier d'en-tête.

NSDate + SameDay.h

@interface NSDate (SameDay)
- (BOOL)isSameDayAsDate:(NSDate*)otherDate;
@end

NSDate + SameDay.m

#import "NSDate+SameDay.h"

@implementation NSDate (SameDay)

- (BOOL)isSameDayAsDate:(NSDate*)otherDate {

    // From progrmr's answer...
    NSCalendar* calendar = [NSCalendar currentCalendar];

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
    NSDateComponents* comp1 = [calendar components:unitFlags fromDate:self];
    NSDateComponents* comp2 = [calendar components:unitFlags fromDate:otherDate];

    return [comp1 day]   == [comp2 day] &&
           [comp1 month] == [comp2 month] &&
           [comp1 year]  == [comp2 year];
}

@end

Ensuite, après avoir importé NSDate+SameDay.h dans votre classe, vous pouvez l'utiliser comme ceci:

if ([myFirstDate isSameDayAsDate:mySecondDate]) {
    // The two dates are on the same day...
}
11
aapierce

J'utilise NSDateComponents pour éliminer l'aspect temps, puis comparer. Quelque chose comme:

if ([[self beginningOfDay:date1] isEqualToDate:[self beginningOfDay:date2]]) 
{
...
}

- (NSDate *)beginningOfDay:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
    NSDateComponents *comp = [calendar components:unitFlags fromDate:date];

    return [calendar dateFromComponents:comp];
}
5
Bruce Geerdes
NSCalendar.currentCalendar().isDateInToday(yourNSDate)

Disponible dans iOS 8.0 et versions ultérieures et OS X v10.9 et versions ultérieures.

4
philipp

dans Swift 3.0, iOS8 +

if NSCalendar.current.isDate(Date(), equalTo: date, toGranularity: .day) {

}

ou

if NSCalendar.current.isDateInToday(date) {

}
1
norbDEV

Existe-t-il un moyen plus facile/meilleur de le faire que d'obtenir les NSDateComponents et de comparer le jour/mois/année?

Oui, il existe un moyen plus simple

-[NSCalendar rangeForUnit:startDate:interval:forDate:] Cette méthode permet de définir facilement une date au début d'une unité (jour, heure, mois, année,…) et d'obtenir la longueur (intervalle) de cette unité.

En tant que catégorie, il pourrait être utilisé comme

@interface NSDate (Comparison)
-(BOOL) isSameDay:(NSDate *)rhs;
@end

@implementation NSDate (Comparison)

-(BOOL)isSameDay:(NSDate *)rhs
{
    NSDate *lhs = self;
    NSDate *lhsStart;
    NSDate *rhsStart;

    NSCalendar *cal = [NSCalendar currentCalendar];
    [cal rangeOfUnit:NSCalendarUnitDay startDate:&lhsStart interval:NULL forDate:lhs];
    [cal rangeOfUnit:NSCalendarUnitDay startDate:&rhsStart interval:NULL forDate:rhs];
    return [lhsStart compare:rhsStart] == NSOrderedSame;
}

@end

Cette catégorie devrait fonctionner pour toutes les versions iOS et Mac OS X 10.5+.

pour iOS 8+ et Mac OS X 10.9+, vous pouvez utiliser NSCalendars

- (BOOL)isDate:(NSDate *)date1 equalToDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit;
1
vikingosegundo