NSDate-Vergleich mit Swift

153

Ich arbeite an einer App, bei der das Fälligkeitsdatum für Hausaufgaben überprüft werden muss. Ich möchte wissen, ob ein Fälligkeitsdatum innerhalb der nächsten Woche liegt und ob es dann eine Aktion ausführt.
Die meiste Dokumentation, die ich finden konnte, befindet sich in Objective-C und ich kann nicht herausfinden, wie es in Swift geht. Danke für die Hilfe!!

Henry Oscannlain-Müller
quelle
2
Swift hat keine Datumsklasse. Sie verwenden die Objective C NSDate-Klasse. Sie haben also die richtige Dokumentation gefunden
mmmmmm
Mögliches Duplikat des Vergleichs von NSDates ohne Zeitkomponente . Es gibt viele sehr gute Antworten.
JWW
Verwandte Antwort: stackoverflow.com/questions/29652771/…
jkdev
2
Swift 3 hat eine DateKlasse. Es ist überbrückt NSDate, aber es heißt Date.
BallpointBen

Antworten:

188

Ich verwende gerne Erweiterungen, um den Code besser lesbar zu machen. Hier sind einige NSDate-Erweiterungen, mit denen Sie Ihren Code bereinigen und leicht verständlich machen können. Ich habe dies in eine sharedCode.swift-Datei eingefügt:

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
    }
}

Wenn Sie so etwas tun können:

//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
quelle
28
Sie sollten Ihren Code vereinfachen. return self.compare(dateToCompare) == NSComparisonResult.OrderedDescending
Olav Gausaker
5
isEqualToDate wird ebenfalls von Apple bereitgestellt. Die Deklaration widerspricht der von Apple definierten.
Shamas S - Wiedereinsetzung Monica
4
Nicht jeden Tag hat 24 Stunden
Leo Dabus
9
Diese Antwort ist schrecklich und sollte niemals die akzeptierte sein. Fügen Sie niemals Zeitintervalle zu von Ihnen erstellten Daten hinzu. Genau deshalb NSDateComponentsgibt es. Es gibt viele Grenzfälle , die nicht ordnungsgemäß zu behandeln sein werden , und es macht keinen Sinn , nicht konform hinzufügen Comparablezu NSDate. Ich würde empfehlen, Johns Lösung zu verwenden .
fpg1503
3
Eine bessere Lösung ist es, NSDate Equatable, Comparable zu machen, dann könnten Sie es einfach tundate1 < date2
aryaxt
209

Wenn Sie unterstützen möchten ==, <, >, <=, oder>= für NSDates, müssen Sie ihn nur irgendwo erklären:

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
quelle
2
@Isuru Comparableist ein Nachkomme des EquatableProtokolls, daher sollten Sie nicht die Konformität mit beiden deklarieren müssen.
John Estropia
2
Nur neugierig, warum es nicht standardmäßig eingebaut ist?!
dVaffection
3
@dVaffection In Objective-C (wo NSDate und Freunde deklariert sind), wenn Sie vergleichen mit ==, <, >etc., werden Sie ein Ergebnis des Vergleichs ihrer Adresse im Speicher bekommen, nicht den Vergleich von ihrem tatsächlichen Wert. In Swift werden sie immer noch als Referenzen behandelt. Ich denke, die Wahl bestand darin, entweder (1) By-Pointer-Vergleiche wie in ObjC beizubehalten oder (2) Verwirrung zu beseitigen, indem keine Implementierung für Vergleiche bereitgestellt wird.
John Estropia
2
Ein zusätzlicher Vorteil dieses Ansatzes besteht darin Array.maxElement(), dass usw. automatisch für Arrays von NSDates verfügbar sind.
pr1001
1
@MarcioCruz Dies ist nur eine schnelle Anforderung, dass alle Operator-Implementierungen im globalen Bereich erfolgen müssen. Siehe die Diskussion hier: stackoverflow.com/questions/35246003/…
John Estropia
54

So vergleichen Sie zwei NSDates in Swift. Ich habe es gerade auf Xcodes Spielplatz getestet:

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

So überprüfen Sie, ob ein Datum dueDateinnerhalb einer Woche liegt:

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)");
}
Rückgängig machen
quelle
2
bedeutet bestellt absteigend, dass Datum1> Datum2?
Henry Oscannlain-Miller
1
Ja, @ Henryoscannlain-Miller.
Rückgängig machen
46

Ich habe es immer in einer Zeile gemacht:

let greater = date1.timeIntervalSince1970 < date2.timeIntervalSince1970

Im ifBlock noch lesbar

Wiedererkennung
quelle
12

In Swift3 implementiert die DateStruktur in Foundationjetzt das ComparableProtokoll. Die bisherigen Swift2- NSDateAnsätze werden also von Swift3 abgelöst 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
}

Hinweis ...

In swift3, Dateist struct, es bedeutet , dass es value type. NSDateist class, es ist 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
quelle
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
quelle
6

Wenn Sie Daten mit der Granularität (nur am selben Tag oder Jahr usw.) auf Swift 3 vergleichen möchten.

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
 }
}

Für andere Kalendervergleiche ändern Sie .day in;

.Jahr .Monat .Tag .Stunde .Minute .Sekunde

SashaZ
quelle
5

Swift implementiert bereits einen Datumsvergleich. Verwenden Sie einfach Datum1> Datum2 und so weiter.

/// 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
quelle
4

In Swift 3 ist Datum vergleichbar, sodass wir Daten wie vergleichen können

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

let isGreater = date1 > date2
print(isGreater)

let isEqual = date1 == date2
print(isEqual)

oder alternativ

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

Besserer Weg, um extensionam Datum zu erstellen

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
  }

}

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

Suhit Patil
quelle
3

Diese Funktion hat bei mir funktioniert, um zu vergleichen, ob ein Datum (startDate) nach dem endDate liegt, wobei beide als NSDate-Variablen definiert wurden:

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

Umsetzung in 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
quelle
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
quelle
1
someArray.sort({($0.dateAdded?.timeIntervalSinceReferenceDate)! < ($1.dateAdded?.timeIntervalSinceReferenceDate)!})

dateAdded ist eine NSDate-Variable in meinem Objekt

class MyClass {
    let dateAdded: NSDate?
}
Larod
quelle
1

Wir haben ein Szenario, um die aktuelle Zeit s / w zweimal (zwei Daten) zu überprüfen. Zum Beispiel möchte ich die aktuelle Zeit zwischen der Öffnungszeit der Klinik (Krankenhaus) und der Schließzeit überprüfen.

Verwenden Sie den einfachen Code.

      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
quelle
1

Für Swift 3 können Sie die folgende Funktion verwenden, um zwischen zwei Daten zu vergleichen.

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 kann entsprechend den Einschränkungen geändert werden, auf die Sie Ihren Vergleich anwenden möchten.

Himanshu
quelle
1

SashaZ erweitern

Schnelles iOS 8 und höher Wenn Sie mehr als nur größere oder kleinere Datumsvergleiche benötigen. Zum Beispiel ist es am selben Tag oder am vorherigen Tag, ...

Hinweis: Vergessen Sie niemals die Zeitzone. Die Kalender-Zeitzone hat eine Standardeinstellung. Wenn Ihnen die Standardeinstellung nicht gefällt, müssen Sie die Zeitzone selbst festlegen. Um zu wissen, welcher Tag heute ist, müssen Sie wissen, in welcher Zeitzone Sie fragen.

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

Verwenden Sie es so:

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

Ein komplexeres Beispiel. Suchen und filtern Sie alle Daten in einem Array, die vom selben Tag wie "findThisDay" stammen:

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
quelle