Swift 3 - Comparando objetos Date

95

Estou atualizando meu aplicativo para a sintaxe Swift 3.0 (sei que ainda está em beta, mas quero estar preparado assim que for lançado).

Até o Beta anterior do Xcode (Beta 5) eu era capaz de comparar dois Dateobjetos usando os operandos <, >e ==. Mas no beta mais recente (beta 6) isso não está mais funcionando. Aqui estão algumas capturas de tela:

insira a descrição da imagem aqui insira a descrição da imagem aqui

Como você pode ver nas duas imagens, são dois Dateobjetos. Mas recebo o seguinte erro: insira a descrição da imagem aqui

O que estou fazendo de errado? As funções ainda são declaradas na Dateclasse:

static func >(Date, Date)

Retorna verdadeiro se a data à esquerda for posterior no tempo do que a data à direita.

Este é apenas um bug Beta ou estou fazendo algo errado?

beeef
fonte
2
let d1 = Date() ; let d2 = Date() ; if d1 > d2 { }funciona no meu Xcode 8 beta 6.
Martin R
1
Sim. - Você deve consultar a mensagem de erro completa no navegador de relatórios.
Martin R
Obrigado @MartinR! Não sabia que posso "mergulhar" em um erro e obter mais informações. Me ajudou muito!
beeef
aceitar a resposta correta
Ankit Thakur

Respostas:

161

Eu tentei este snippet (no Xcode 8 Beta 6) e está funcionando bem.

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

if date1 == date2 { ... }
else if date1 > date2 { ... }
else if date1 < date2 { ... }
Ankit Thakur
fonte
se eu quiser ignorar o tempo. por exemplo, 2019-05-14 12:08:14 +0000== 2019-05-14deve retornar verdadeiro. então o que ?
Awais Fayyaz
@AwaisFayyaz Se você quiser comparar datas sem levar um DateComponent em consideração. Você precisa obter os componentes que deseja a partir da data. Em seguida, obtenha a data de DateComponents e compare-os.
Giorgio Doganiero
52

Dateé Comparable& Equatable(a partir do Swift 3)

Esta resposta complementa a resposta de @Ankit Thakur.

Desde o Swift 3, a Dateestrutura (com base na NSDateclasse subjacente ) adota os protocolos Comparablee Equatable.

  • Comparableexige que Dateimplementar os operadores: <, <=, >, >=.
  • Equatablerequer que Dateimplemente o ==operador.
  • Equatablepermite Dateusar a implementação padrão do !=operador (que é o inverso da Equatable ==implementação do operador).

O código de exemplo a seguir exercita esses operadores de comparação e confirma quais comparações são verdadeiras com as printinstruções.

Função de comparação

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

Uso de amostra

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
Dan móvel
fonte
31

do Swift 3 e superior, a data é comparável para que possamos comparar diretamente datas como

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)

Alternativamente, podemos criar extensão na data

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

Usar: let isEqual = date1.isEqualTo(date2)

Suhit Patil
fonte
se eu quiser ignorar o tempo. por exemplo, 2019-05-14 12:08:14 +0000== 2019-05-14deve retornar verdadeiro. então o que ?
Awais Fayyaz
15

Olhe este http://iswift.org/cookbook/compare-2-dates

Obter datas:

// Get current date
let dateA = NSDate()

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

Usando a instrução 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")
}

usando declaração IF

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

 //OR

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

 }
Luis Abreu Acevedo
fonte
9

Para mim, o problema era que eu tinha minha própria extensão para a classe Date que definia todos os operadores de comparação. Agora (desde o swift 3) essa data é comparável, essas extensões não são necessárias. Então, eu comentei e funcionou.

Jitendra Kulkarni
fonte
7

SWIFT 3: Não sei se é isso que você está procurando. Mas comparo uma string a um carimbo de data / hora atual para ver se minha string é mais antiga que agora.

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

Para usá-lo:

if (checkTimeStamp(date:"2016-11-21 12:00:00") == false) {
    // Do something
}
NB
fonte
5

Para comparar a data apenas com ano - mês - dia e sem tempo para mim funcionava assim:

     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
fonte
5

Se você quiser ignorar os segundos, por exemplo, você pode usar

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

Exemplo compare se for o mesmo dia:

Calendar.current.isDate(date1, equalTo: date2, toGranularity: .day)
Zdravko Zdravkin
fonte
1

A partir do momento em que escrevo, Swift nativamente suporta comparando datas com todos os operadores de comparação (ou seja <, <=, ==, >=, e >). Você também pode comparar datas opcionais, mas estão limitados a <, ==, e >. Se você precisar comparar duas datas opcionais usando <=ou >=, ou seja,

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

Você pode sobrecarregar os operadores <=e >=para oferecer suporte a opcionais:

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
}
NSExceptional
fonte
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
fonte
1

Outra maneira de fazer isso:

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

        case .orderedDescending:
            break;

        case .orderedSame:
            break
    }
Shadros
fonte
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
fonte
1

Swift 5:

1) Se você usar o tipo de data:

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

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

2) Se você usar o tipo 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 

Não tenho certeza ou a segunda opção funciona a 100%. Mas por quanto eu não mudaria os valores de firstStringDate e secondStringDate se o resultado estivesse correto.

Maxwell
fonte
1

no Swift 3,4 você deve usar "Comparar". por exemplo:

DateArray.sort { (($0)?.compare($1))! == .orderedDescending }
Alireza
fonte