web-dev-qa-db-fra.com

Comment vérifier si un NSDate se produit entre deux autres NSDates

J'essaie de déterminer si la date actuelle est comprise dans une plage de dates à l'aide de NSDate.

Par exemple, vous pouvez obtenir la date et l'heure actuelles à l'aide de NSDate:

NSDate rightNow = [NSDate date];

Je voudrais ensuite utiliser cette date pour vérifier si elle est dans la plage de 9 heures-17 heures.

88
Brock Woolf

Je suis venu avec une solution. Si vous avez une meilleure solution, n'hésitez pas à la laisser et je la marquerai comme correcte.

+ (BOOL)date:(NSDate*)date isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate
{
    if ([date compare:beginDate] == NSOrderedAscending)
        return NO;

    if ([date compare:endDate] == NSOrderedDescending) 
        return NO;

    return YES;
}
160
Brock Woolf

Pour la première partie, utilisez la réponse de @kperryua pour construire les objets NSDate avec lesquels vous souhaitez comparer. De votre réponse à votre propre question, il semble que vous ayez compris cela.

Pour comparer réellement les dates, je suis tout à fait d’accord avec le commentaire de @Tim sur votre réponse. C'est plus concis mais en réalité exactement équivalent à votre code, et je vais vous expliquer pourquoi.

+ (BOOL) date:(NSDate*)date isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate {
    return (([date compare:beginDate] != NSOrderedAscending) && ([date compare:endDate] != NSOrderedDescending));
}

Bien qu'il puisse sembler que l'instruction return doit évaluer les deux opérandes de l'opérateur &&, ce n'est en réalité pas le cas. La clé est " court-circuit evaluation ", qui est implémentée dans une grande variété de langages de programmation, et certainement en C. En gros, les opérateurs & et && "court-circuit" si le premier argument est 0 (ou NO, nil, etc.), tandis que | et || font la même chose si le premier argument est not 0. Si date vient avant beginDate, le test renvoie NO sans même avoir besoin de comparer avec endDate. En gros, il fait la même chose que votre code, mais dans une seule déclaration sur une ligne, pas 5 (ou 7, avec des espaces).

Ceci est conçu comme une contribution constructive, car lorsque les programmeurs comprennent la manière dont leur langage de programmation évalue les expressions logiques, ils peuvent les construire plus efficacement sans trop d’efficacité. Cependant, il existe des tests similaires qui seraient moins efficaces, étant donné que tous les opérateurs ne font pas de court-circuit. (En effet, la plupart des ne peuvent pas court-circuits, tels que les opérateurs de comparaison numériques.) En cas de doute, il est toujours prudent de clarifier la logique, mais le code peut être beaucoup plus lisible lorsque/compilateur gère les petites choses pour vous.

14
Quinn Taylor

Version de Brock Woolf dans Swift:

extension NSDate
{
    func isBetweenDates(beginDate: NSDate, endDate: NSDate) -> Bool
    {
        if self.compare(beginDate) == .OrderedAscending
        {
            return false
        }

        if self.compare(endDate) == .OrderedDescending
        {
            return false
        }

        return true
    }
}
8
ChikabuZ

Si vous voulez savoir si la date actuelle se situe entre deux moments donnés (9h - 17h le 7/1/09), utilisez NSCalendar et NSDateComponents pour créer des instances NSDate aux heures souhaitées et comparez-les à la date du jour.

Si vous voulez savoir si la date actuelle se situe entre ces deux heures toutes jours, vous pouvez probablement procéder dans l'autre sens. Créez un objet NSDateComponents avec et NSCalendar et votre NSDate et comparez les composants horaires.

5
kperryua

Ceci peut être accompli facilement en utilisant les intervalles de temps des dates, comme ceci:

const NSTimeInterval i = [date timeIntervalSinceReferenceDate];
return ([startDate timeIntervalSinceReferenceDate] <= i &&
        [endDate timeIntervalSinceReferenceDate] >= i);
4
justin

Poursuivre avec les solutions de Quinn et de Brock est très agréable de mettre en œuvre l’implémentation de NSDate afin qu’il puisse être utilisé partout comme ceci:

-(BOOL) isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate {
    return (([self compare:beginDate] != NSOrderedAscending) && ([self compare:endDate] != NSOrderedDescending));
}

Et à n'importe quelle partie de votre code, vous pouvez l'utiliser comme:

[myNSDate isBetweenDate:thisNSDate andDate:thatNSDate];

(myNSDate, thisNSDate et thatNSDate sont bien sûr des NSDates :) 

3
MiQUEL

Si vous pouvez cibler iOS 10.0 +/macOS 10.12+, utilisez la classe DateInterval.

Tout d’abord, créez un intervalle de dates avec une date de début et de fin:

let start: Date = Date()
let middle: Date = Date()
let end: Date = Date()

let dateInterval: DateInterval = DateInterval(start: start, end: end)

Ensuite, vérifiez si la date est dans l'intervalle en utilisant la méthode contains de DateInterval:

let dateIsInInterval: Bool = dateInterval.contains(middle) // true
2
Bryan Luby

Il existe une solution meilleure et plus rapide à ce problème.

extention Date {
    func isBetween(from startDate: Date,to endDate: Date) -> Bool {
        let result = (min(startDate, endDate) ... max(startDate, endDate)).contains(self)
        return result
    }
}

Ensuite, vous pouvez l'appeler comme ça.

todayDate.isBetween(from: startDate, to: endDate)

Même vous pouvez passer la date au hasard car cette extension vérifie lequel est minimum et lequel n’est pas.

vous pouvez l'utiliser dans Swift 3 et au-dessus.

2
Rehan Ali

Avec Swift 4.2 et iOS 12, vous pouvez utiliser l'une des deux solutions ci-dessous afin de vérifier si une date se situe entre deux autres dates.


#1. Utilisation de la méthode DateInterval's contains(_:)

DateInterval a une méthode appelée contains(_:) . contains(_:) a la déclaration suivante:

func contains(_ date: Date) -> Bool

Indique si cet intervalle contient la date donnée.

Le code de terrain de jeu suivant montre comment utiliser contains(_:) afin de vérifier si une date se produit entre deux autres dates: 

import Foundation

let calendar = Calendar.current
let startDate = calendar.date(from: DateComponents(year: 2010, month: 11, day: 22))!
let endDate = calendar.date(from: DateComponents(year: 2015, month: 5, day: 1))!
let myDate = calendar.date(from: DateComponents(year: 2012, month: 8, day: 15))!

let dateInterval = DateInterval(start: startDate, end: endDate)
let result = dateInterval.contains(myDate)
print(result) // prints: true

# 2. Utilisation de la méthode ClosedRange's contains(_:)

ClosedRange a une méthode appelée contains(_:) . contains(_:) a la déclaration suivante:

func contains(_ element: Bound) -> Bool

Retourne une valeur booléenne indiquant si l'élément donné est contenu dans la plage.

Le code de terrain de jeu suivant montre comment utiliser contains(_:) afin de vérifier si une date se produit entre deux autres dates: 

import Foundation

let calendar = Calendar.current
let startDate = calendar.date(from: DateComponents(year: 2010, month: 11, day: 22))!
let endDate = calendar.date(from: DateComponents(year: 2015, month: 5, day: 1))!
let myDate = calendar.date(from: DateComponents(year: 2012, month: 8, day: 15))!

let range = startDate ... endDate
let result = range.contains(myDate)
//let result = range ~= myDate // also works
print(result) // prints: true
0
Imanou Petit

Une meilleure version dans Swift:

@objc public class DateRange: NSObject {
    let startDate: Date
    let endDate: Date

    init(startDate: Date, endDate: Date) {
        self.startDate = startDate
        self.endDate = endDate
    }

    @objc(containsDate:)
    func contains(_ date: Date) -> Bool {
        let startDateOrder = date.compare(startDate)
        let endDateOrder = date.compare(endDate)
        let validStartDate = startDateOrder == .orderedAscending || startDateOrder == .orderedSame
        let validEndDate = endDateOrder == .orderedDescending || endDateOrder == .orderedSame
        return validStartDate && validEndDate
    }
}
0
TheCodingArt