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?


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

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

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)


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

 }

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.


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
}

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)

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

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
}

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

1

Inny sposób na zrobienie tego:

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

        case .orderedDescending:
            break;

        case .orderedSame:
            break
    }

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

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.


1

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

DateArray.sort { (($0)?.compare($1))! == .orderedDescending }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.