web-dev-qa-db-fra.com

Comment déterminer si un NSDate est aujourd'hui?

Comment vérifier si une NSDate appartient à aujourd'hui?

J'avais l'habitude de le vérifier en utilisant les 10 premiers caractères de [aDate description]. [[aDate description] substringToIndex:10] renvoie une chaîne semblable à "YYYY-MM-DD". J'ai donc comparé la chaîne à la chaîne renvoyée par [[[NSDate date] description] substringToIndex:10].

Y at-il plus moyen rapide et/ou soigné de vérifier?

Merci.

145
Seunghoon

Dans macOS 10.9+ et iOS 8+, une méthode sur NSCalendar/Calendar fait exactement cela!

- (BOOL)isDateInToday:(NSDate *)date 

Donc vous feriez simplement

Objectif c:

BOOL today = [[NSCalendar currentCalendar] isDateInToday:date];

Swift 3:

let today = Calendar.current.isDateInToday(date)
291
Catfish_Man

Vous pouvez comparer les composants de date:

NSDateComponents *otherDay = [[NSCalendar currentCalendar] components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:aDate];
NSDateComponents *today = [[NSCalendar currentCalendar] components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:[NSDate date]];
if([today day] == [otherDay day] &&
   [today month] == [otherDay month] &&
   [today year] == [otherDay year] &&
   [today era] == [otherDay era]) {
    //do stuff
}

Modifier:

J'aime plus la méthode de stefan, je pense que cela donne une déclaration plus propre et plus compréhensible si:

NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:[NSDate date]];
NSDate *today = [cal dateFromComponents:components];
components = [cal components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:aDate];
NSDate *otherDate = [cal dateFromComponents:components];

if([today isEqualToDate:otherDate]) {
    //do stuff
}

Chris, j'ai intégré votre suggestion. Je devais regarder quelle époque était, alors pour ceux qui ne le savent pas, cela fait une distinction entre la Colombie-Britannique et la Colombie-Britannique. C'est probablement inutile pour la plupart des gens, mais il est facile à vérifier et ajoute une certitude, alors je l'ai inclus. Si vous visez la vitesse, ce n’est probablement pas une bonne méthode.


NOTEcomme avec beaucoup de réponses sur SO, après 7 ans, c'est totalement obsolète. Dans Swift, utilisez simplement .isDateInToday

192
David Kanarek

Ceci est une ramification de votre question, mais si vous souhaitez imprimer un NSDate avec "Aujourd'hui" ou "Hier", utilisez la fonction

- (void)setDoesRelativeDateFormatting:(BOOL)b

pour NSDateFormatter

27
Jon

Je voudrais essayer d'obtenir la date d'aujourd'hui normalisée à minuit et la deuxième date, normaliser à minuit puis comparer si c'est le même NSDate.

De un exemple Apple voici comment vous normalisez à minuit la date du jour, faites de même pour la deuxième date et comparez:

NSCalendar * gregorian = [[NSCalendar alloc]
                               initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents * components =
    [gregorian components:
                 (NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit)
                 fromDate:[NSDate date]];
NSDate * today = [gregorian dateFromComponents:components];
16
stefanB

Travailler Extension Swift 3 & 4 de la suggestion de Catfish_Man:

extension Date {

    func isToday() -> Bool {
        return Calendar.current.isDateInToday(self)
    }

}
13
Benno Kress

Pas besoin de jongler avec des composants, des époques et des choses. 

NSCalendar fournit une méthode pour obtenir le début d'une certaine unité de temps pour une date existante.

Ce code aura le début d'aujourd'hui et une autre date et comparera cela. Si la valeur est NSOrderedSame, les deux dates ont lieu le même jour, donc aujourd'hui.

NSDate *today = nil;
NSDate *beginningOfOtherDate = nil;

NSDate *now = [NSDate date];
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&today interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&beginningOfOtherDate interval:NULL forDate:beginningOfOtherDate];

if([today compare:beginningOfOtherDate] == NSOrderedSame) {
    //otherDate is a date in the current day
}
12
vikingosegundo
extension NSDate {
  func isToday() -> Bool {
    let cal = NSCalendar.currentCalendar()
    var components = cal.components([.Era, .Year, .Month, .Day], fromDate:NSDate())
    let today = cal.dateFromComponents(components)!

    components = cal.components([.Era, .Year, .Month, .Day], fromDate:self)
    let otherDate = cal.dateFromComponents(components)!

    return today.isEqualToDate(otherDate)
}

Travaillé pour moi sur Swift 2.0

8
Omar Albeik

Version rapide de la meilleure réponse:

let cal = NSCalendar.currentCalendar()
var components = cal.components([.Era, .Year, .Month, .Day], fromDate:NSDate())
let today = cal.dateFromComponents(components)!

components = cal.components([.Era, .Year, .Month, .Day], fromDate:aDate);
let otherDate = cal.dateFromComponents(components)!

if(today.isEqualToDate(otherDate)) {
    //do stuff
}
6
Vojtech Vrbka

Vous pouvez également vérifier l'intervalle de temps entre la date que vous avez et la date du jour:

[myDate timeIntervalSinceNow]

Cela vous donnera l'intervalle de temps, en secondes, entre myDate et la date/heure actuelle.

Lien .

Edit: Note pour tout le monde: Je suis bien conscient que [myDate timeIntervalSinceNow] ne détermine pas sans ambiguïté si myDate est aujourd'hui.

Je laisse cette réponse telle quelle afin que, si quelqu'un recherche quelque chose de similaire et qu'il soit utile [myDate timeIntervalSinceNow], il se peut qu'il le trouve ici.

5
alesplin

Reportez-vous à l'entrée de documentation d'Apple intitulée "Effectuer des calculs de calendrier" [lien] .

Le Listing 13 sur cette page suggère que pour déterminer le nombre de minuit entre les jours, vous utilisez:

- (NSInteger)midnightsFromDate:(NSDate *)startDate toDate:(NSDate *)endDate
{
    NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
    NSInteger startDay = [calendar ordinalityOfUnit:NSDayCalendarUnit
                                             inUnit:NSEraCalendarUnit
                                            forDate:startDate];
    NSInteger endDay = [calendar ordinalityOfUnit:NSDayCalendarUnit
                                           inUnit:NSEraCalendarUnit
                                          forDate:endDate];
    return endDay - startDay;
}

Vous pouvez ensuite déterminer si deux jours sont identiques en utilisant cette méthode et en vérifiant s’il renvoie 0 ou non.

5
ArtOfWarfare

Swift Extension basé sur les meilleures réponses:

extension NSDate {
    func isToday() -> Bool {
        let cal = NSCalendar.currentCalendar()
        if cal.respondsToSelector("isDateInToday:") {
            return cal.isDateInToday(self)
        }
        var components = cal.components((.CalendarUnitEra | .CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay), fromDate:NSDate())
        let today = cal.dateFromComponents(components)!

        components = cal.components((.CalendarUnitEra | .CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay), fromDate:self);
        let otherDate = cal.dateFromComponents(components)!
        return today.isEqualToDate(otherDate)
    }
}
4
ZiggyST

Il existe un moyen plus facile que la plupart des réponses ci-dessus! 

NSDate *date = ... // The date you wish to test
NSCalendar *calendar = [NSCalendar currentCalendar];

if([calendar isDateInToday:date]) {
    //do stuff
}
2
aryland

Si vous avez beaucoup de comparaisons de dates, les appels à calendar:components:fromDate commencent à prendre beaucoup de temps. Selon certains profils que j'ai faits, ils semblent être assez coûteux.

Supposons que vous tentiez de déterminer quelles dates, par exemple NSArray *datesToCompare, sont identiques à un jour donné, par exemple NSDate *baseDate, vous pouvez utiliser un des paramètres suivants (partiellement adapté d'une réponse ci-dessus):

NSDate *baseDate = [NSDate date];

NSArray *datesToCompare = [NSArray arrayWithObjects:[NSDate date], 
                           [NSDate dateWithTimeIntervalSinceNow:100],
                           [NSDate dateWithTimeIntervalSinceNow:1000],
                           [NSDate dateWithTimeIntervalSinceNow:-10000],
                           [NSDate dateWithTimeIntervalSinceNow:100000],
                           [NSDate dateWithTimeIntervalSinceNow:1000000],
                           [NSDate dateWithTimeIntervalSinceNow:50],
                           nil];

// determine the NSDate for midnight of the base date:
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* comps = [calendar components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) 
                                       fromDate:baseDate];
NSDate* theMidnightHour = [calendar dateFromComponents:comps];

// set up a localized date formatter so we can see the answers are right!
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];

// determine which dates in an array are on the same day as the base date:
for (NSDate *date in datesToCompare) {
    NSTimeInterval interval = [date timeIntervalSinceDate:theMidnightHour];
    if (interval >= 0 && interval < 60*60*24) {
        NSLog(@"%@ is on the same day as %@", [dateFormatter stringFromDate:date], [dateFormatter stringFromDate:baseDate]);
    }
    else {
        NSLog(@"%@ is NOT on the same day as %@", [dateFormatter stringFromDate:date], [dateFormatter stringFromDate:baseDate]);
    }
}

Sortie:

Nov 23, 2011 1:32:00 PM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 1:33:40 PM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 1:48:40 PM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 10:45:20 AM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 24, 2011 5:18:40 PM is NOT on the same day as Nov 23, 2011 1:32:00 PM
Dec 5, 2011 3:18:40 AM is NOT on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 1:32:50 PM is on the same day as Nov 23, 2011 1:32:00 PM
2
Julian Richardson

pour iOS7 et les versions antérieures:

//this is now => need that for the current date
NSDate * now = [NSDate date];

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone systemTimeZone]];

NSDateComponents * components = [calendar components:( NSYearCalendarUnit|    NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate: now];

[components setMinute:0];
[components setHour:0];
[components setSecond:0];

//this is Today's Midnight
NSDate *todaysMidnight = [calendar dateFromComponents: components];



//now timeIntervals since Midnight => in seconds
NSTimeInterval todayTimeInterval = [now timeIntervalSinceDate: todaysMidnight];

//now timeIntervals since OtherDate => in seconds
NSTimeInterval otherDateTimeInterval = [now timeIntervalSinceDate: otherDate];

if(otherDateTimeInterval > todayTimeInterval) //otherDate is not in today
{
    if((otherDateTimeInterval - todayTimeInterval) <= 86400) //86400 == a day total seconds
    {
        @"yesterday";
    }
    else
    {
        @"earlier";
    }
}
else
{
    @"today";
}


now = nil;
calendar = nil;
components = nil;
todaysMidnight = nil;

NSLog("Thank you :-)");
0
user3744424

Cela pourrait probablement être retravaillé en tant que catégorie NSDate, mais j’ai utilisé:

// Seconds per day (24h * 60m * 60s)
#define kSecondsPerDay 86400.0f

+ (BOOL) dateIsToday:(NSDate*)dateToCheck
{
    // Split today into components
    NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents* comps = [gregorian components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit) 
                                        fromDate:[NSDate date]];

    // Set to this morning 00:00:00
    [comps setHour:0];
    [comps setMinute:0];
    [comps setSecond:0];
    NSDate* theMidnightHour = [gregorian dateFromComponents:comps];
    [gregorian release];

    // Get time difference (in seconds) between date and then
    NSTimeInterval diff = [dateToCheck timeIntervalSinceDate:theMidnightHour];
    return ( diff>=0.0f && diff<kSecondsPerDay );
}

(Cependant, comparer les deux chaînes de date comme dans la question initiale semble presque "plus propre" ..) 

0
LeoN

Consultez notre superbe NSDate extension d'Erica Sadun. Très simple à utiliser. C'est bon ici:

http://github.com/erica/NSDate-Extensions

C'est déjà là dans cet article: https://stackoverflow.com/a/4052798/362310

0
Vaibhav Saran

La solution correcte et sûre sans décompression forcée, fonctionnant sur Swift 2.2 et avant iOS 8:

func isToday() -> Bool {
    let calendar = NSCalendar.currentCalendar()
    if #available(iOS 8.0, *) {
        return calendar.isDateInToday(self)
    }

    let todayComponents = calendar.components([.Era, .Year, .Month, .Day], fromDate:NSDate())
    let dayComponents = calendar.components([.Era, .Year, .Month, .Day], fromDate:self)

    guard let today = calendar.dateFromComponents(todayComponents),
        day = calendar.dateFromComponents(dayComponents) else {
        return false
    }

    return today.compare(day) == .OrderedSame
}
0
fpg1503