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
Viewcontroller Slide Animation
Can the Conversion of a String to Data with Utf-8 Encoding Ever Fail
Compare Textfield.Text to Firebase String Swift
How to Validate Dynamically Added Textfields on a Button Click in Swiftui
Swift - Firebase Search in Database
Apply Vertical Alpha Gradient to Uitableview
How to Remove Spaces from a String in Swift
Swiftui Foreach Based on State Int
Add a Line as a Selection Indicator to a Uitabbaritem in Swift
How to Create a String from Utf8 in Swift
How to Handle Closure Recursivity
Skphysicsbody Avoid Collision Swift/Spritekit
Fibonacci Calculator Stack Overflows at 93Nd Number in Swift