web-dev-qa-db-fra.com

Comment comparez-vous juste l'heure d'une date dans Swift?

J'ai deux objets de date:

  1. 2017-01-13 11:40:17 +0000

  2. 2016-03-15 10:22:14 +0000

Je dois comparer juste l'heure de ces valeurs et ignorer la date

exemple: 12h00 et 12h01, 12h01 est plus tard donc (12h01> 12h00) == true

10
Dylan

C'est l'itinéraire que j'ai suivi à la fin, ce qui facilite la comparaison de l'heure d'une date dans Swift

Heure du nouvel objet:

class Time: Comparable, Equatable {
init(_ date: Date) {
    //get the current calender
    let calendar = Calendar.current

    //get just the minute and the hour of the day passed to it
    let dateComponents = calendar.dateComponents([.hour, .minute], from: date)

        //calculate the seconds since the beggining of the day for comparisions
        let dateSeconds = dateComponents.hour! * 3600 + dateComponents.minute! * 60

        //set the varibles
        secondsSinceBeginningOfDay = dateSeconds
        hour = dateComponents.hour!
        minute = dateComponents.minute!
    }

    init(_ hour: Int, _ minute: Int) {
        //calculate the seconds since the beggining of the day for comparisions
        let dateSeconds = hour * 3600 + minute * 60

        //set the varibles
        secondsSinceBeginningOfDay = dateSeconds
        self.hour = hour
        self.minute = minute
    }

    var hour : Int
    var minute: Int

    var date: Date {
        //get the current calender
        let calendar = Calendar.current

        //create a new date components.
        var dateComponents = DateComponents()

        dateComponents.hour = hour
        dateComponents.minute = minute

        return calendar.date(byAdding: dateComponents, to: Date())!
    }

    /// the number or seconds since the beggining of the day, this is used for comparisions
    private let secondsSinceBeginningOfDay: Int

    //comparisions so you can compare times
    static func == (lhs: Time, rhs: Time) -> Bool {
        return lhs.secondsSinceBeginningOfDay == rhs.secondsSinceBeginningOfDay
    }

    static func < (lhs: Time, rhs: Time) -> Bool {
        return lhs.secondsSinceBeginningOfDay < rhs.secondsSinceBeginningOfDay
    }

    static func <= (lhs: Time, rhs: Time) -> Bool {
        return lhs.secondsSinceBeginningOfDay <= rhs.secondsSinceBeginningOfDay
    }


    static func >= (lhs: Time, rhs: Time) -> Bool {
        return lhs.secondsSinceBeginningOfDay >= rhs.secondsSinceBeginningOfDay
    }


    static func > (lhs: Time, rhs: Time) -> Bool {
        return lhs.secondsSinceBeginningOfDay > rhs.secondsSinceBeginningOfDay
    }
}

Extension de date pour un accès facile: // Ajoute la possibilité d'obtenir simplement l'heure d'une date:

extension Date {
    var time: Time {
        return Time(self)
    }
}

Exemple:

let firstDate = Date()
let secondDate = firstDate

//Will return true
let timeEqual = firstDate.time == secondDate.time
12
Dylan

Mon approche serait d'utiliser Calendar pour en faire des objets Date avec le même jour, puis de les comparer en utilisant par exemple timeIntervalSinceReferenceDate .

Un autre, plus propre (mais très probablement avec plus de lignes de code résultant) serait de créer une extension pour Date appelée secondsFromBeginningOfTheDay() -> TimeInterval puis de comparer les valeurs doubles résultantes.

Exemple basé sur la deuxième approche:

// Creating Date from String
let textDate1 = "2017-01-13T12:21:00-0800"
let textDate2 = "2016-03-06T20:12:05-0900"

let dateFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZ"
    formatter.timeZone = TimeZone.current
    return formatter
} ()

// Dates used for the comparison
let date1 = dateFormatter.date(from: textDate1)
let date2 = dateFormatter.date(from: textDate2)




// Date extensions
extension Date {
    func secondsFromBeginningOfTheDay() -> TimeInterval {
        let calendar = Calendar.current
        // omitting fractions of seconds for simplicity
        let dateComponents = calendar.dateComponents([.hour, .minute, .second], from: self)

        let dateSeconds = dateComponents.hour! * 3600 + dateComponents.minute! * 60 + dateComponents.second!

        return TimeInterval(dateSeconds)
    }

    // Interval between two times of the day in seconds
    func timeOfDayInterval(toDate date: Date) -> TimeInterval {
        let date1Seconds = self.secondsFromBeginningOfTheDay()
        let date2Seconds = date.secondsFromBeginningOfTheDay()
        return date2Seconds - date1Seconds
    }
}

if let date1 = date1, let date2 = date2 {
    let diff = date1.timeOfDayInterval(toDate: date2)

    // as text
    if diff > 0 {
        print("Time of the day in the second date is greater")
    } else if diff < 0 {
        print("Time of the day in the first date is greater")
    } else {
        print("Times of the day in both dates are equal")
    }


    // show interval as as H M S
    let timeIntervalFormatter = DateComponentsFormatter()
    timeIntervalFormatter.unitsStyle = .abbreviated
    timeIntervalFormatter.allowedUnits = [.hour, .minute, .second]
    print("Difference between times since midnight is", timeIntervalFormatter.string(from: diff) ?? "n/a")

}

// Output: 
// Time of the day in the second date is greater
// Difference between times since midnight is 8h 51m 5s
7
MirekE

J'ai eu un problème en faisant cela et je pense que j'ai trouvé une solution plus simple si vous voulez simplement comparer l'heure de deux dates. Il se sent un peu "hacky" mais semble bien fonctionner.

Swift 4

// date1 and date2 are the dates you want to compare

let calendar = Calendar.current

var newDate = Date(TimeIntervalSinceReferenceDate: 0) // Initiates date at 2001-01-01 00:00:00 +0000
var newDate1 = Date(TimeIntervalSinceReferenceDate: 0) // Same as above

// Recieving the components from the dates you want to compare 
let newDateComponents = calendar.dateComponents([.hour, .minute], from: date1)!
let newDate1Components = calendar.dateComponents([.hour, .minute], from: date2)!

// Adding those components
newDate = calendar.date(byAdding: newDateComponents, to: newDate)
newDate1 = calendar.date(byAdding: newDate1Components, to: newDate1)
5
Bartek Spitza

Ma solution pour comparer deux heures de la journée en ignorant la date:

let date1 = some time as a date
let date2 = some other time as a date

let time1 = 60*Calendar.current.component(.hour, from: date1!) + Calendar.current.component(.minute, from: date1!)
let time2 =  60*Calendar.current.component(.hour, from: date2!) + Calendar.current.component(.minute, from: date2!)

Vous pouvez maintenant comparer les entiers time1 et time2 sans tenir compte du jour. Vous pouvez ajouter les secondes/60 si vous avez besoin de plus de précision.

4
Wayne Henderson

Il n'y a pas de type standard pour une heure du jour. Un type raisonnable pour commencer est juste un tuple:

typealias TimeOfDay = (hour: Int, minute: Int, second: Int)

Pour créer ces valeurs TimeOfDay, vous aurez besoin d'un Calendar. Par défaut, un Calendar utilise le fuseau horaire du système à l'échelle du périphérique. Si vous ne le souhaitez pas, définissez explicitement le fuseau horaire de Calendar. Exemple:

var calendar = Calendar.autoupdatingCurrent
calendar.timeZone = TimeZone(abbreviation: "UTC")!

Vous pouvez maintenant utiliser un DateFormatter pour convertir les chaînes en Dates (si nécessaire), puis utiliser calendar pour extraire les composants de l'heure du Dates:

let strings: [String] = ["2017-01-13 11:40:17 +0000", "2016-03-15 10:22:14 +0000"]
let parser = DateFormatter()
parser.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let timesOfDay: [TimeOfDay] = strings.map({ (string) -> TimeOfDay in
    let components = calendar.dateComponents([.hour, .minute, .second], from: parser.date(from: string)!)
    return (hour: components.hour!, minute: components.minute!, second: components.second!)
})

Swift.print(timesOfDay)
// Output: [(11, 40, 17), (10, 22, 14)]

Enfin, vous pouvez comparer ces valeurs TimeOfDay. Swift est livré avec des opérateurs de comparaison standard pour les tuples dont les éléments sont Comparable, donc ce type TimeOfDay est admissible. Vous pouvez simplement dire ceci:

if timesOfDay[0] < timesOfDay[1] {
    Swift.print("date[0] comes first")
} else if timesOfDay[0] == timesOfDay[1] {
    Swift.print("times are equal")
} else {
    Swift.print("date[1] comes first")
}
2
rob mayoff

C'est très simple dans Swift si vous utilisez Swifter Swift

date1.day = 1
date1.month = 1
date1.year = 2000

date2.day = 1
date2.month = 1
date2.year = 2000

vous pouvez maintenant utiliser les opérateurs>, <, == à date1 et date2 pour comparer uniquement les composants temporels.

modifier - vous pouvez le faire vous-même en étendant la classe de date, par exemple swifter-Swift fait le soufflet pour le composant jour.

public var day: Int {
        get {
            return Calendar.current.component(.day, from: self)
        }
        set {
            let allowedRange = Calendar.current.range(of: .day, in: .month, for: self)!
            guard allowedRange.contains(newValue) else { return }

            let currentDay = Calendar.current.component(.day, from: self)
            let daysToAdd = newValue - currentDay
            if let date = Calendar.current.date(byAdding: .day, value: daysToAdd, to: self) {
                self = date
            }
        }
    } 
1
Alex

Ce code fonctionne, vérifiez-le facilement dans la cour de récréation

let s1 = "22:31"
let s2 = "14:31"
let f = DateFormatter()
f.dateFormat = "HH:mm"

f.date(from: s1)! //"Jan 1, 2000 at 10:31 PM"
f.date(from: s2)! //"Jan 1, 2000 at 2:31 PM"
f.date(from: s1)! > f.date(from: s2)!  // true
0
John Eugene