Swift 3 - Porównywanie obiektów Date

96

Aktualizuję moją aplikację do składni Swift 3.0 (wiem, że wciąż jest w wersji beta, ale chcę być przygotowany, gdy tylko zostanie wydany).

Aż do poprzedniej wersji beta Xcode (beta 5) udało mi się porównanie dwóch Dateobiektów za pomocą argumentów <, >a ==. Ale w najnowszej wersji beta (Beta 6) to już nie działa. Oto kilka zrzutów ekranu:

wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj

Jak widać na obu zrzutach ekranu, są to dwa Dateobiekty. Ale pojawia się następujący błąd: wprowadź opis obrazu tutaj

Co ja robię źle? Funkcje są nadal deklarowane w Dateklasie:

static func >(Date, Date)

Zwraca wartość true, jeśli data po lewej stronie jest późniejsza niż data po prawej stronie.

Czy to tylko błąd Beta, czy robię coś nie tak?

wołowina
źródło
2
let d1 = Date() ; let d2 = Date() ; if d1 > d2 { }działa w mojej Xcode 8 beta 6.
Martin R
1
Tak. - W nawigatorze raportów należy odszukać cały komunikat o błędzie.
Martin R
Dziękuję @MartinR! Nie wiedziałem, że mogę „zanurkować” w błąd i uzyskać więcej informacji. Bardzo mi pomogło!
wołowina
zaakceptuj poprawną odpowiedź
Ankit Thakur

Odpowiedzi:

163

Wypróbowałem ten fragment (w Xcode 8 Beta 6) i działa dobrze.

let date1 = Date()
let date2 = Date().addingTimeInterval(100)

if date1 == date2 { ... }
else if date1 > date2 { ... }
else if date1 < date2 { ... }
Ankit Thakur
źródło
jeśli chcę ignorować czas. np. 2019-05-14 12:08:14 +0000== 2019-05-14powinno zwrócić prawdę. co wtedy?
Awais Fayyaz
@AwaisFayyaz Jeśli chcesz porównać daty bez uwzględnienia komponentu DateComponent. Musisz zdobyć żądane komponenty od daty. Następnie uzyskaj datę z DateComponents i porównaj je.
Giorgio Doganiero
52

Dateto Comparable& Equatable(od Swift 3)

Ta odpowiedź uzupełnia odpowiedź @Ankit Thakur.

Od wersji Swift 3 Datestruktura (oparta na NSDateklasie bazowej ) przyjmuje protokoły Comparablei Equatable.

  • Comparablewymaga Datewdrożenia operatorów: <, <=, >, >=.
  • Equatablewymaga Datewdrożenia ==operatora.
  • Equatablepozwala Datena użycie domyślnej implementacji !=operatora (która jest odwrotnością Equatable ==implementacji operatora).

Poniższy przykładowy kod sprawdza te operatory porównania i potwierdza, które porównania są prawdziwe z printinstrukcjami.

Funkcja porównania

import Foundation

func describeComparison(date1: Date, date2: Date) -> String {

    var descriptionArray: [String] = []

    if date1 < date2 {
        descriptionArray.append("date1 < date2")
    }

    if date1 <= date2 {
        descriptionArray.append("date1 <= date2")
    }

    if date1 > date2 {
        descriptionArray.append("date1 > date2")
    }

    if date1 >= date2 {
        descriptionArray.append("date1 >= date2")
    }

    if date1 == date2 {
        descriptionArray.append("date1 == date2")
    }

    if date1 != date2 {
        descriptionArray.append("date1 != date2")
    }

    return descriptionArray.joined(separator: ",  ")
}

Przykładowe użycie

let now = Date()

describeComparison(date1: now, date2: now.addingTimeInterval(1))
// date1 < date2,  date1 <= date2,  date1 != date2

describeComparison(date1: now, date2: now.addingTimeInterval(-1))
// date1 > date2,  date1 >= date2,  date1 != date2

describeComparison(date1: now, date2: now)
// date1 <= date2,  date1 >= date2,  date1 == date2
Mobile Dan
źródło
31

od wersji Swift 3 i nowszych Data jest porównywalna, dzięki czemu możemy bezpośrednio porównywać daty, takie jak

let date1 = Date()
let date2 = Date().addingTimeInterval(50)

let isGreater = date1 > date2
print(isGreater)

let isSmaller = date1 < date2
print(isSmaller)

let isEqual = date1 == date2
print(isEqual)

Alternatywnie możemy utworzyć rozszerzenie w dniu

extension Date {

  func isEqualTo(_ date: Date) -> Bool {
    return self == date
  }
  
  func isGreaterThan(_ date: Date) -> Bool {
     return self > date
  }
  
  func isSmallerThan(_ date: Date) -> Bool {
     return self < date
  }
}

Posługiwać się: let isEqual = date1.isEqualTo(date2)

Suhit Patil
źródło
jeśli chcę ignorować czas. np. 2019-05-14 12:08:14 +0000== 2019-05-14powinno zwrócić prawdę. co wtedy?
Awais Fayyaz
16

Spójrz na http://iswift.org/cookbook/compare-2-dates

Pobierz daty:

// Get current date
let dateA = NSDate()

// Get a later date (after a couple of milliseconds)
let dateB = NSDate()

Korzystanie z instrukcji SWITCH

// Compare them
switch dateA.compare(dateB) {
    case .OrderedAscending     :   print("Date A is earlier than date B")
    case .OrderedDescending    :   print("Date A is later than date B")
    case .OrderedSame          :   print("The two dates are the same")
}

przy użyciu instrukcji IF

 if dateA.compare(dateB) == .orderedAscending {
     datePickerTo.date = datePicker.date
 }

 //OR

 if case .orderedAcending = dateA.compare(dateB) {

 }
Luis Abreu Acevedo
źródło
9

Dla mnie problem polegał na tym, że miałem własne rozszerzenie klasy Date, które definiowało wszystkie operatory porównania. Teraz (od swift 3), że Date jest porównywalna, te rozszerzenia nie są potrzebne. Więc skomentowałem je i zadziałało.

Jitendra Kulkarni
źródło
8

SWIFT 3: Nie wiem, czy tego właśnie szukasz. Ale porównuję ciąg z bieżącym znacznikiem czasu, aby sprawdzić, czy mój ciąg jest teraz starszy.

func checkTimeStamp(date: String!) -> Bool {
        let dateFormatter: DateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        dateFormatter.locale = Locale(identifier:"en_US_POSIX")
        let datecomponents = dateFormatter.date(from: date)

        let now = Date()

        if (datecomponents! >= now) {
            return true
        } else {
            return false
        }
    }

Aby z niego skorzystać:

if (checkTimeStamp(date:"2016-11-21 12:00:00") == false) {
    // Do something
}
NB
źródło
6

Jeśli chcesz na przykład zignorować sekundy, możesz użyć

func isDate (Date, equalTo: Date, toUnitGranularity: NSCalendar.Unit) -> Bool

Przykładowe porównanie, jeśli jest tego samego dnia:

Calendar.current.isDate(date1, equalTo: date2, toGranularity: .day)
zdravko zdravkin
źródło
5

Aby porównać datę tylko z rokiem - miesiącem - dniem i bez czasu u mnie działało tak:

     let order = Calendar.current.compare(self.startDate, to: compareDate!, toGranularity: .day)  

                      switch order {
                        case .orderedAscending:
                            print("\(gpsDate) is after \(self.startDate)")
                        case .orderedDescending:
                            print("\(gpsDate) is before \(self.startDate)")
                        default:
                            print("\(gpsDate) is the same as \(self.startDate)")
                        }
Alessandro Mattiuzzi
źródło
1

Począwszy od chwili pisania tego tekstu, Swift natywnie obsługuje porównywanie dat z wszystkich operatorów porównania (to znaczy <,<= , ==, >=, i >). Można również porównać opcjonalnymi terminami ale są ograniczone do <, ==, i >. Jeśli chcesz porównać dwie opcjonalne daty za pomocą <=lub >=, tj

let date1: Date? = ...
let date2: Date? = ...
if date1 >= date2 { ... }

Możesz przeciążać plik <=>= operatory i , aby obsługiwać opcje:

func <= <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
    return lhs == rhs || lhs < rhs
}

func >= <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
    return lhs == rhs || lhs > rhs
}
Wyjątkowe
źródło
1
extension Date {
 func isBetween(_ date1: Date, and date2: Date) -> Bool {
    return (min(date1, date2) ... max(date1, date2)).contains(self)
  }
}

let resultArray = dateArray.filter { $0.dateObj!.isBetween(startDate, and: endDate) }
Arjun Patel
źródło
1

Inny sposób na zrobienie tego:

    switch date1.compare(date2) {
        case .orderedAscending:
            break

        case .orderedDescending:
            break;

        case .orderedSame:
            break
    }
Shadros
źródło
1
   var strDateValidate = ""
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd"

            let firstDate = dateFormatter.date(from:lblStartTime.text!)
            let secondDate = dateFormatter.date(from:lblEndTime.text!)

            if firstDate?.compare(secondDate!) == .orderedSame || firstDate?.compare(secondDate!) == .orderedAscending {
                print("Both dates are same or first is less than scecond")
                strDateValidate = "yes"
            }
            else
            {
                //second date is bigger than first
                strDateValidate = "no"
            }

            if strDateValidate == "no"
            {
                alertView(message: "Start date and end date for a booking must be equal or Start date must be smaller than the end date", controller: self)
            }
Davender Verma
źródło
1

Swift 5:

1) Jeśli używasz typu daty:

let firstDate  = Date()
let secondDate = Date()

print(firstDate > secondDate)  
print(firstDate < secondDate)
print(firstDate == secondDate)

2) Jeśli używasz typu String:

let firstStringDate  = "2019-05-22T09:56:00.1111111"
let secondStringDate = "2019-05-22T09:56:00.2222222"

print(firstStringDate > secondStringDate)  // false
print(firstStringDate < secondStringDate)  // true
print(firstStringDate == secondStringDate) // false 

Nie jestem pewien lub druga opcja działa na 100%. Ale o ile nie zmieniłbym wartości firstStringDate i secondStringDate, wynik był poprawny.

maxwell
źródło
1

w Swift 3,4 należy użyć opcji „Porównaj”. na przykład:

DateArray.sort { (($0)?.compare($1))! == .orderedDescending }
Alireza
źródło