Swift: Compare Date by Days

Swift: Compare date by days

Details

  • Xcode 11.5 (11E608c), Swift 5.1

Idea

base on usage dateComponents(_:from:to:) function

Solution

import Foundation

extension Date {

func fullDistance(from date: Date, resultIn component: Calendar.Component, calendar: Calendar = .current) -> Int? {
calendar.dateComponents([component], from: self, to: date).value(for: component)
}

func distance(from date: Date, only component: Calendar.Component, calendar: Calendar = .current) -> Int {
let days1 = calendar.component(component, from: self)
let days2 = calendar.component(component, from: date)
return days1 - days2
}

func hasSame(_ component: Calendar.Component, as date: Date) -> Bool {
distance(from: date, only: component) == 0
}
}

Full Sample

Do not forget to put here the Solution code (look above)

var dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy hh:mm:ss"
//dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)

let smallerDate = dateFormatter.date(from: "01-01-2012 00:05:01")!
let biggerDate = dateFormatter.date(from: "03-12-2019 09:30:01")!

print(smallerDate.fullDistance(from: biggerDate, resultIn: .day)) // Optional(2893)
print(biggerDate.fullDistance(from: smallerDate, resultIn: .day)) // Optional(-2893)
print(smallerDate.fullDistance(from: biggerDate, resultIn: .year)) // Optional(7)
print(biggerDate.fullDistance(from: smallerDate, resultIn: .year)) // Optional(7)
print(smallerDate.fullDistance(from: biggerDate, resultIn: .hour)) // Optional(69441)
print(biggerDate.fullDistance(from: smallerDate, resultIn: .hour)) // Optional(-69441)

print(smallerDate.distance(from: biggerDate, only: .day)) // -2
print(biggerDate.distance(from: smallerDate, only: .day)) // 2
print(smallerDate.distance(from: biggerDate, only: .year)) // -7
print(biggerDate.distance(from: smallerDate, only: .year)) // 7
print(smallerDate.distance(from: biggerDate, only: .hour)) // -9
print(biggerDate.distance(from: smallerDate, only: .hour)) // 9

print(smallerDate.hasSame(.day, as: biggerDate)) // false
print(biggerDate.hasSame(.second, as: smallerDate)) // true

Comparing two dates in swift in order to check if a day has gone by

Your code cannot work.

The logic is supposed to be:

  • Get the day from UserDefaults,
  • Compare it to the current day.
  • If the values are not equal save the new day to UserDefaults

class UserInfoViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

let dateToday = Calendar.current.component(.day, from: Date())
let dateToCompare = UserDefaults.standard.integer(forKey: "userDefaultDate")
if dateToCompare != dateToCompare {
UserDefaults.standard.set(dateToday, forKey: "userDefaultDate")
resetLabel.isHidden = false
} else {
resetLabel.isHidden = true
}
}
}

Note:

Never use value(forKey: with UserDefaults.

There are many convenience methods and for objects use object(forKey:

Edit

It's more reliable to save the Date object and compare using isDateInToday of Calendar

class UserInfoViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

let dateToday = Date()
let calendar = Calendar.current
let dateToCompare = UserDefaults.standard.object(forKey: "userDefaultDate") as? Date ?? Date.distantPast
if calendar.isDateInToday(dateToCompare) {
resetLabel.isHidden = true
} else {
UserDefaults.standard.set(dateToday, forKey: "userDefaultDate")
resetLabel.isHidden = false
}
}
}

How can i compare two dates (NSDate) in Swift 3 and get the days between them?

Simply make extension of Date like this and get difference in days.

extension Date {
func daysBetweenDate(toDate: Date) -> Int {
let components = Calendar.current.dateComponents([.day], from: self, to: toDate)
return components.day ?? 0
}
}

Now use this extension like this

let numOfDays = fromDate.daysBetweenDate(toDate: toDate)

You can use DateFormatter to convert String to Date like this.

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
dateFormatter.timeZone = TimeZone(abbreviation: "GMT")
let date = dateFormatter.date(from: "18-11-2016")

Compare Date to String Date Value Swift

There is a better way to check if two dates are in the same day

let currentDate = Date()
let selectedDate = Date()
if Calendar.current.isDate(currentDate, inSameDayAs: selectedDate) {
print("yes")
} else {
print("no")
}

Compare DateComponents in swift

You can create dates from the DateComponents and compare them. You can make DateComponents conform to Comparable:

extension DateComponents: Comparable {
public static func < (lhs: DateComponents, rhs: DateComponents) -> Bool {
let now = Date()
let calendar = Calendar.current
return calendar.date(byAdding: lhs, to: now)! < calendar.date(byAdding: rhs, to: now)!
}
}

Then you can do those comparisons:

DateComponents(year: 1) > DateComponents(month: 15) // => false
DateComponents(day: 10) > DateComponents(weekOfMonth: 1) // => true

You might also want to make it Equatable:

extension DateComponents: Equatable {
public static func == (lhs: DateComponents, rhs: DateComponents) -> Bool {
let now = Date()
let calendar = Calendar.current
return calendar.date(byAdding: lhs, to: now)! == calendar.date(byAdding: rhs, to: now)!
}
}

Disclaimer: This revised answer is using the current date/time as the reference to ensure meaningful comparison of days and months (give that the number of days per month can change). Questions like “are there more than 30 days in a month” only makes sense if the caller supplies a reference date or we use “now” (which is what I’ve done above).

Note, by using “now” as the reference date, then comparisons like “which is greater, 24 hours or 1 day” will now incorporate daylight savings (e.g., depending upon whether your calendar will “spring forward”, “fall back”, or, the vast majority of the time, not change at all).

Calculating the difference between two dates in Swift

I ended up creating a custom operator for Date:

extension Date {

static func - (lhs: Date, rhs: Date) -> TimeInterval {
return lhs.timeIntervalSinceReferenceDate - rhs.timeIntervalSinceReferenceDate
}

}

With this operator I can now compute the difference between two dates on a more abstract level without caring about timeIntervalSinceReferenceDate or what exactly the reference date is – and without losing precision, for example:

let delta = toDate - fromDate

Obviously, I didn't change much, but for me it's a lot more readable and consequent: Swift has the + operator already implemented for a Date and a TimeInterval:

/// Returns a `Date` with a specified amount of time added to it.
public static func + (lhs: Date, rhs: TimeInterval) -> Date

So it's already supporting

Date + TimeInterval = Date

Consequently, it should also support

Date - Date = TimeInterval

in my opinion and that's what I added with the simple implementation of the - operator. Now I can simply write the example function exactly as mentioned in my question:

func computeNewDate(from fromDate: Date, to toDate: Date) -> Date    
let delta = toDate - fromDate // `Date` - `Date` = `TimeInterval`
let today = Date()
if delta < 0 {
return today
} else {
return today + delta // `Date` + `TimeInterval` = `Date`
}
}

It might very well be that this has some downsides that I'm not aware of at this moment and I'd love to hear your thoughts on this.

How do you compare just the time of a Date in Swift?

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


Related Topics



Leave a reply



Submit