How do you compare just the time of a Date in Swif

2020-02-26 09:19发布

I have two Date Objects:

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

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

I need to compare just the time of these values and ignore the date

example: 12:00am and 12:01am, 12:01 is later so (12:01am > 12:00am) == true

6条回答
Ridiculous、
2楼-- · 2020-02-26 09:34

My approach would be to use Calendar to make them Date objects with the same day and then comparing them using for example timeIntervalSinceReferenceDate.

Another, cleaner (but most likely with more lines of resulting code) would be to create extension for Date called secondsFromBeginningOfTheDay() -> TimeInterval and then comparing the resulting double values.

Example based on the second approach:

// 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
查看更多
家丑人穷心不美
3楼-- · 2020-02-26 09:42

This is very simple in Swift if you use Swifter Swift

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

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

now you can use >,<,== operators on date1 and date2 to compare just the time components.

edit - you could do this your self by extending the date class, for example swifter-swift does the bellow for the day component.

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
            }
        }
    } 
查看更多
来,给爷笑一个
4楼-- · 2020-02-26 09:47

This is the route I took in the end, which makes it easy to compare just the time of a Date in swift

New Object Time:

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

Date Extension for easy access: //Adds ability to just get the time from a date:

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

Example:

let firstDate = Date()
let secondDate = firstDate

//Will return true
let timeEqual = firstDate.time == secondDate.time
查看更多
小情绪 Triste *
5楼-- · 2020-02-26 09:47

I had a problem doing just this and I think I found a simpler solution if you just want to compare the time of two dates. It does feel a little "hacky" but seems to work well.

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)
查看更多
欢心
6楼-- · 2020-02-26 09:51

My solution for comparing two times of day while ignoring the 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!)

Now you can compare the integers time1 and time2 without regard to the day. You could add the seconds/60 if you need more precision.

查看更多
The star\"
7楼-- · 2020-02-26 09:55

There's no standard type for a time-of-day. A reasonable type to start with is just a tuple:

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

To create these TimeOfDay values, you'll need a Calendar. By default, a Calendar uses the device's system-wide time zone. If you don't want that, set the Calendar's time zone explicitly. Example:

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

Now you can use a DateFormatter to convert strings to Dates (if necessary), and then use calendar to extract the time-of-day components from the 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)]

Finally, you can compare these TimeOfDay values. Swift comes with standard comparison operators for tuples whose elements are Comparable, so this TimeOfDay type qualifies. You can just say this:

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")
}
查看更多
登录 后发表回答