Comparaison NSDate avec Swift

153

Je travaille sur une application qui nécessite de vérifier la date d'échéance des devoirs. Je veux savoir si une date d'échéance est dans la semaine prochaine, et si c'est alors effectuer une action.
La plupart de la documentation que j'ai pu trouver est en Objective-C et je ne peux pas comprendre comment le faire dans Swift. Merci pour l'aide!!

Henry Oscannlain-Miller
la source
2
swift n'a pas de classe de date que vous utilisez la classe Objective C NSDate - vous avez donc trouvé la documentation correcte
mmmmmm
Copie possible de la comparaison des NSDates sans composante de temps . Il y a beaucoup de très bonnes réponses.
jww
Réponse associée: stackoverflow.com/questions/29652771/…
jkdev
2
Swift 3 a une Dateclasse. Il est relié à NSDate, mais il est appelé Date.
BallpointBen

Réponses:

188

J'aime utiliser des extensions pour rendre le code plus lisible. Voici quelques extensions NSDate qui peuvent vous aider à nettoyer votre code et à le rendre facile à comprendre. Je mets ceci dans un fichier sharedCode.swift:

extension NSDate {

    func isGreaterThanDate(dateToCompare: NSDate) -> Bool {
        //Declare Variables
        var isGreater = false

        //Compare Values
        if self.compare(dateToCompare as Date) == ComparisonResult.orderedDescending {
            isGreater = true
        }

        //Return Result
        return isGreater
    }

    func isLessThanDate(dateToCompare: NSDate) -> Bool {
        //Declare Variables
        var isLess = false

        //Compare Values
        if self.compare(dateToCompare as Date) == ComparisonResult.orderedAscending {
            isLess = true
        }

        //Return Result
        return isLess
    }

    func equalToDate(dateToCompare: NSDate) -> Bool {
        //Declare Variables
        var isEqualTo = false

        //Compare Values
        if self.compare(dateToCompare as Date) == ComparisonResult.orderedSame {
            isEqualTo = true
        }

        //Return Result
        return isEqualTo
    }

    func addDays(daysToAdd: Int) -> NSDate {
        let secondsInDays: TimeInterval = Double(daysToAdd) * 60 * 60 * 24
        let dateWithDaysAdded: NSDate = self.addingTimeInterval(secondsInDays)

        //Return Result
        return dateWithDaysAdded
    }

    func addHours(hoursToAdd: Int) -> NSDate {
        let secondsInHours: TimeInterval = Double(hoursToAdd) * 60 * 60
        let dateWithHoursAdded: NSDate = self.addingTimeInterval(secondsInHours)

        //Return Result
        return dateWithHoursAdded
    }
}

Maintenant, si vous pouvez faire quelque chose comme ça:

//Get Current Date/Time
var currentDateTime = NSDate()

//Get Reminder Date (which is Due date minus 7 days lets say)
var reminderDate = dueDate.addDays(-7)

//Check if reminderDate is Greater than Right now
if(reminderDate.isGreaterThanDate(currentDateTime)) {
    //Do Something...
}
user2266987
la source
28
Vous devez simplifier votre code. return self.compare(dateToCompare) == NSComparisonResult.OrderedDescending
Olav Gausaker
5
isEqualToDate est également fourni par Apple. Sa déclaration est en conflit avec celle définie par Apple.
Shamas S - Réintégrer Monica le
4
Pas tous les jours a 24 heures
Leo Dabus
9
Cette réponse est terrible et ne devrait jamais être acceptée. N'ajoutez jamais d' intervalles de temps aux dates que vous avez créées. C'est précisément pourquoi NSDateComponentsexister. Il y a beaucoup de cas extrêmes qui ne sont pas gérés correctement et cela n'a aucun sens de ne pas ajouter de conformité Comparableà NSDate. Je recommanderais d'utiliser la solution de John .
fpg1503
3
Une meilleure solution est de rendre NSDate Equatable, Comparable, alors vous pouvez simplement le fairedate1 < date2
aryaxt
209

Si vous voulez soutenir ==, <, >, <=ou >=pour NSDates, il vous suffit de déclarer quelque part:

public func ==(lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs === rhs || lhs.compare(rhs) == .OrderedSame
}

public func <(lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.compare(rhs) == .OrderedAscending
}

extension NSDate: Comparable { }
John Estropia
la source
2
@Isuru Comparableest un descendant du Equatableprotocole, vous ne devriez donc pas avoir besoin de déclarer la conformité aux deux.
John Estropia
2
Vous êtes simplement curieux de savoir pourquoi il n'est pas intégré par défaut?!
dVaffection
3
@dVaffection Dans Objective-C (où NSDate et les amis sont déclarés), si vous comparez à l' aide ==, <, >, etc., vous allez recevoir un résultat de la comparaison de leur adresse en mémoire, et non la comparaison de leur valeur réelle. Dans Swift, ils sont toujours traités comme des références, donc je pense que le choix était de (1) conserver les comparaisons par pointeur telles qu'elles sont dans ObjC, ou (2) d'éliminer la confusion en ne fournissant pas d'implémentation pour les comparaisons.
John Estropia
2
Un avantage supplémentaire de cette approche est que Array.maxElement(), etc. est alors automatiquement disponible des tableaux de NSDates.
pr1001 le
1
@MarcioCruz C'est juste une exigence Swift selon laquelle toutes les implémentations d'opérateurs doivent être à l'échelle mondiale. Voir la discussion ici: stackoverflow.com/questions/35246003/…
John Estropia
54

Voici comment vous comparez deux NSDates dans Swift, je viens de le tester dans le terrain de jeu de Xcode:

if date1.compare(date2) == NSComparisonResult.OrderedDescending
{
    NSLog("date1 after date2");
} else if date1.compare(date2) == NSComparisonResult.OrderedAscending
{
    NSLog("date1 before date2");
} else
{
    NSLog("dates are equal");
}

Donc, pour vérifier si une date dueDateest dans une semaine à partir de maintenant:

let dueDate=...

let calendar = NSCalendar.currentCalendar()
let comps = NSDateComponents()
comps.day = 7
let date2 = calendar.dateByAddingComponents(comps, toDate: NSDate(), options: NSCalendarOptions.allZeros)

if dueDate.compare(date2!) == NSComparisonResult.OrderedDescending
{
    NSLog("not due within a week");
} else if dueDate.compare(date2!) == NSComparisonResult.OrderedAscending
{
    NSLog("due within a week");
} else
{
    NSLog("due in exactly a week (to the second, this will rarely happen in practice)");
}
Annuler
la source
2
ordonné Décroissant signifie que date1> date2?
Henry oscannlain-miller
1
Oui, @ Henryoscannlain-miller.
Annuler
46

Je l'ai toujours fait en une seule ligne:

let greater = date1.timeIntervalSince1970 < date2.timeIntervalSince1970

Toujours lisible dans le ifbloc

ReDétection
la source
12

Dans Swift3, la Datestructure dans Foundationmaintenant implémente le Comparableprotocole. Ainsi, les précédentes NSDateapproches Swift2 sont remplacées par Swift3 Date.

/**
 `Date` represents a single point in time.

 A `Date` is independent of a particular calendar or time zone. To represent a `Date` to a user, you must interpret it in the context of a `Calendar`.
*/
public struct Date : ReferenceConvertible, Comparable, Equatable {

    // .... more         

    /**
        Returns the interval between the receiver and another given date.

        - Parameter another: The date with which to compare the receiver.

        - Returns: The interval between the receiver and the `another` parameter. If the receiver is earlier than `anotherDate`, the return value is negative. If `anotherDate` is `nil`, the results are undefined.

        - SeeAlso: `timeIntervalSince1970`
        - SeeAlso: `timeIntervalSinceNow`
        - SeeAlso: `timeIntervalSinceReferenceDate`
        */
    public func timeIntervalSince(_ date: Date) -> TimeInterval

   // .... more 

    /// Returns true if the two `Date` values represent the same point in time.
    public static func ==(lhs: Date, rhs: Date) -> Bool

    /// Returns true if the left hand `Date` is earlier in time than the right hand `Date`.
    public static func <(lhs: Date, rhs: Date) -> Bool

    /// Returns true if the left hand `Date` is later in time than the right hand `Date`.
    public static func >(lhs: Date, rhs: Date) -> Bool

    /// Returns a `Date` with a specified amount of time added to it.
    public static func +(lhs: Date, rhs: TimeInterval) -> Date

    /// Returns a `Date` with a specified amount of time subtracted from it.
    public static func -(lhs: Date, rhs: TimeInterval) -> Date

  // .... more
}

Remarque ...

Dans Swift3, Datec'est struct, cela signifie que c'est le cas value type. NSDatec'est class, ça l'est reference type.

// Swift3
let a = Date()
let b = a //< `b` will copy `a`. 

// So, the addresses between `a` and `b` are different.
// `Date` is some kind different with `NSDate`.
AechoLiu
la source
6
extension NSDate {

    // MARK: - Dates comparison

    func isGreaterThanDate(dateToCompare: NSDate) -> Bool {

        return self.compare(dateToCompare) == NSComparisonResult.OrderedDescending
    }

    func isLessThanDate(dateToCompare: NSDate) -> Bool {

        return self.compare(dateToCompare) == NSComparisonResult.OrderedAscending
    }

    func equalToDate(dateToCompare: NSDate) -> Bool {

        return self.compare(dateToCompare) == NSComparisonResult.OrderedSame
    }
}
Yura Voevodin
la source
6

Si vous souhaitez comparer les dates avec la granularité (juste le même jour ou l'année, etc.) sur swift 3.

func compareDate(date1:NSDate, date2:NSDate, toUnitGranularity: NSCalendar.Unit) -> Bool {

 let order = NSCalendar.current.compare(date1 as Date, to: date2 as Date, toGranularity: .day)
 switch order {
 case .orderedSame:
   return true
 default:
   return false
 }
}

Pour les autres comparaisons de calendrier, remplacez .day par;

.année .mois .jour .heure .minute .seconde

SashaZ
la source
5

Swift implémente déjà la comparaison de date, utilisez simplement date1> date2 et ainsi de suite.

/// Returns true if the two `Date` values represent the same point in time.
public static func ==(lhs: Date, rhs: Date) -> Bool

/// Returns true if the left hand `Date` is earlier in time than the right hand `Date`.
public static func <(lhs: Date, rhs: Date) -> Bool

/// Returns true if the left hand `Date` is later in time than the right hand `Date`.
public static func >(lhs: Date, rhs: Date) -> Bool

/// Returns a `Date` with a specified amount of time added to it.
public static func +(lhs: Date, rhs: TimeInterval) -> Date

/// Returns a `Date` with a specified amount of time subtracted from it.
public static func -(lhs: Date, rhs: TimeInterval) -> Date

/// Add a `TimeInterval` to a `Date`.
///
/// - warning: This only adjusts an absolute value. If you wish to add calendrical concepts like hours, days, months then you must use a `Calendar`. That will take into account complexities like daylight saving time, months with different numbers of days, and more.
public static func +=(lhs: inout Date, rhs: TimeInterval)

/// Subtract a `TimeInterval` from a `Date`.
///
/// - warning: This only adjusts an absolute value. If you wish to add calendrical concepts like hours, days, months then you must use a `Calendar`. That will take into account complexities like daylight saving time, months with different numbers of days, and more.
public static func -=(lhs: inout Date, rhs: TimeInterval)
Trung Phan
la source
4

dans Swift 3, la date est comparable afin que nous puissions comparer directement des dates telles que

let date1 = Date()
let date2 = Date()

let isGreater = date1 > date2
print(isGreater)

let isEqual = date1 == date2
print(isEqual)

Ou bien

let result = date1.compare(date2)
switch result {
    case .OrderedAscending     :   print("date 1 is earlier than date 2")
    case .OrderedDescending    :   print("date 1 is later than date 2")
    case .OrderedSame          :   print("two dates are the same")
}

meilleure façon de créer extensionà la date

extension Date {

  fun isGreater(than date: Date) -> Bool {
    return self > date 
  }

  func isSmaller(than date: Date) -> Bool {
    return self < date
  }

  func isEqual(to date: Date) -> Bool {
    return self == date
  }

}

usage let isGreater = date1.isGreater(than: date2)

Suhit Patil
la source
3

Cette fonction a fonctionné pour moi pour comparer si une date (startDate) était après la date de fin où les deux ont été définies comme des variables NSDate:

if startDate.compare(endDate as Date) == ComparisonResult.orderedDescending
Diskprotek
la source
2

mise en œuvre dans Swift

let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let files = NSFileManager.defaultManager().contentsOfDirectoryAtPath(documentsPath, error: nil)

let filesAndProperties = NSMutableArray()
for file in files! {

    let filePath = documentsPath.stringByAppendingString(file as NSString)
    let properties = NSFileManager.defaultManager().attributesOfItemAtPath(filePath, error: nil)
    let modDate = properties![NSFileModificationDate] as NSDate
    filesAndProperties.addObject(NSDictionary(objectsAndKeys: file, "path", modDate, "lastModDate"))
}

let sortedFiles = filesAndProperties.sortedArrayUsingComparator({
    (path1, path2) -> NSComparisonResult in

    var comp = (path1.objectForKey("lastModDate") as NSDate).compare(path2.objectForKey("lastModDate") as NSDate)
    if comp == .OrderedDescending {

        comp = .OrderedAscending
    } else if comp == .OrderedAscending {

        comp = .OrderedDescending
    }

    return comp
})
János
la source
2
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateData: String = dateFormatter.stringFromDate(date1)
let testDate: String = dateFormatter.stringFromDate(date2)
print(dateData == testDate)
Trevor Jordet
la source
1
someArray.sort({($0.dateAdded?.timeIntervalSinceReferenceDate)! < ($1.dateAdded?.timeIntervalSinceReferenceDate)!})

dateAdded est une variable NSDate dans mon objet

class MyClass {
    let dateAdded: NSDate?
}
larod
la source
1

Nous avons un scénario pour vérifier les mensonges de l'heure actuelle b / w deux fois (deux dates) .Par exemple, je veux vérifier le mensonge actuel entre l'heure d'ouverture de la clinique (hôpital) et l'heure de fermeture.

Utilisez le code simple.

      NSDate * now = [NSDate date];
        NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
        [outputFormatter setDateFormat:@"HH:mm:ss"];

        //current time
        NSString *currentTimeString = [outputFormatter stringFromDate:now];
        NSDate *dateCurrent = [outputFormatter dateFromString:currentTimeString];


        NSString *timeStart = @"09:00:00";
        NSString *timeEnd = @"22:00:00";

        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"HH:mm:ss"];

        NSDate *dateStart= [formatter timeStart];
        NSDate *dateEnd = [formatter timeEnd];
        NSComparisonResult result = [dateCurrent compare:dateStart];
        NSComparisonResult resultSecond = [date2 compare:dateEnd];

if(result == NSOrderedDescending && resultSecond == NSOrderedDescending)
        {
            NSLog(@"current time lies in starting and end time");
    }else {
            NSLog(@"current time doesn't lie in starting and end time");
        }
Maninderjit Singh
la source
1

Pour swift 3, vous pouvez utiliser la fonction ci-dessous pour comparer entre deux dates.

func compareDate(dateInitial:Date, dateFinal:Date) -> Bool {
    let order = Calendar.current.compare(dateInitial, to: dateFinal, toGranularity: .day)
    switch order {
    case .orderedSame:
        return true
    default:
        return false
    }
}

toGranularity peut être modifié en fonction des contraintes sur lesquelles vous souhaitez appliquer votre comparaison.

Himanshu
la source
1

Pour prolonger sur SashaZ

Swift iOS 8 et plus Lorsque vous avez besoin de plus que de simples comparaisons de dates plus grandes ou plus petites. Par exemple, est-ce le même jour ou la veille, ...

Remarque: n'oubliez jamais le fuseau horaire. Le fuseau horaire du calendrier a une valeur par défaut, mais si vous n'aimez pas la valeur par défaut, vous devez définir le fuseau horaire vous-même. Pour savoir de quel jour il s'agit, vous devez savoir dans quel fuseau horaire vous demandez.

extension Date {
    func compareTo(date: Date, toGranularity: Calendar.Component ) -> ComparisonResult  {
        var cal = Calendar.current
        cal.timeZone = TimeZone(identifier: "Europe/Paris")!
        return cal.compare(self, to: date, toGranularity: toGranularity)
        }
    }

Utilisez-le comme ceci:

if thisDate.compareTo(date: Date(), toGranularity: .day) == .orderedDescending {
// thisDate is a previous day
}

D'un exemple plus complexe. Recherchez et filtrez toutes les dates dans un tableau, qui sont du même jour que "findThisDay":

let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "Europe/Paris")
formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"

let findThisDay = formatter.date(from: "2018/11/05 08:11:08")!
_ = [
    formatter.date(from: "2018/12/05 08:08:08")!, 
    formatter.date(from: "2018/11/05 08:11:08")!,
    formatter.date(from: "2018/11/05 11:08:22")!,
    formatter.date(from: "2018/11/05 22:08:22")!,
    formatter.date(from: "2018/11/05 08:08:22")!,
    formatter.date(from: "2018/11/07 08:08:22")!,
    ]
    .filter{ findThisDay.compareTo(date: $0 , toGranularity: .day) == .orderedSame }
    .map { print(formatter.string(from: $0)) }
t1ser
la source