Reputation: 5891
The way I did this in Swift 2.3 was:
let currentDate = NSDate()
let currentCalendar = NSCalendar.currentCalendar()
var startDate : NSDate?
var endDate : NSDate?
// The following two lines set the `startDate` and `endDate` to the start of the day
currentCalendar.rangeOfUnit(.Day, startDate: &startDate, interval: nil, forDate: currentDate)
currentCalendar.rangeOfUnit(.Day, startDate: &endDate, interval: nil, forDate: self)
let intervalComps = currentCalendar.components([.Day], fromDate: startDate!, toDate: endDate!, options: [])
print(intervalComps.day)
Now this has all changed with Swift 3. I have to either use NSCalendar
and NSDate
by constantly type casting with as
, or find the Swift 3 way of doing it.
What's the right way to do it in Swift 3?
Upvotes: 63
Views: 72871
Reputation: 787
Found this on a different thread, but it was finally the most simple solution for me using Swift 4:
let previousDate = ENTER DATE HERE
let now = Date()
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .brief // or other options
formatter.allowedUnits = [.month, .day, .hour]
formatter.maximumUnitCount = 1 // Show one unit, eg 1d vs. 1d 6hrs)
let stringDate = formatter.string(from: previousDate, to: now)
This will give you a result such as say 2m
(two months ago) or 7h
(seven hours ago). You can simply ...
formatter.allowedUnits = [.day]
That will give it as days alone, eg 71d
or 0d
.
Upvotes: 3
Reputation: 683
private func days(actual day1:[Int],expect day2:[Int]) -> Int {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let first = "\(day1[2])-\(day1[1])-\(day1[0])"
let firstDate = dateFormatter.date(from:first)!
let last = "\(day2[2])-\(day2[1])-\(day2[0])"
let lastDate = dateFormatter.date(from:last)!
let currentCalendar = NSCalendar.current
let components = currentCalendar.dateComponents([.day], from: firstDate, to: lastDate)
return components.day!
}
Another approach to compare with components of day month year
Usage:
Input the dates in following format
[dd, mm, yyyy]
[9, 6, 2017]
[6, 6, 2017]
Upvotes: 0
Reputation: 1954
In Swift 5 there is a simple one-liner to get the number of days (or any other DateComponent) between two dates:
let diffInDays = Calendar.current.dateComponents([.day], from: dateA, to: dateB).day
Note: As pointed out in the comments, this solution measures the 24h periods and therefore requires at least 24h between dateA
and dateB
.
Upvotes: 120
Reputation: 3701
import Foundation
extension DateComponents {
func dateComponentsToTimeString() -> String {
var hour = "\(self.hour!)"
var minute = "\(self.minute!)"
var second = "\(self.second!)"
if self.hour! < 10 { hour = "0" + hour }
if self.minute! < 10 { minute = "0" + minute }
if self.second! < 10 { second = "0" + second }
let str = "\(hour):\(minute):\(second)"
return str
}
}
extension Date {
func offset(from date: Date)-> DateComponents {
let components = Set<Calendar.Component>([.second, .minute, .hour, .day, .month, .year])
let differenceOfDate = Calendar.current.dateComponents(components, from: date, to: self)
return differenceOfDate
}
}
Use:
var durationString: String {
return self.endTime.offset(from: self.startTime).dateComponentsToTimeString()
}
Upvotes: 1
Reputation: 4259
If someone would need to display all time units e.g "hours minutes seconds" not just "hours". Let's say the time difference between two dates is 1hour 59minutes 20seconds. This function will display "1h 59m 20s".
Here is my code:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'hh:mm:ss"
let start = dateFormatter.date(from: "2019-01-31T07:45:00")!
let end = dateFormatter.date(from: "2019-03-01T06:30:00")!
print("Date Difference : ", end.offsetFrom(date: start))
Function Definition:
extension Date {
func offsetFrom(date : Date) -> String {
let dayHourMinuteSecond: Set = [.day, .hour, .minute, .second]
let difference = NSCalendar.current.dateComponents(dayHourMinuteSecond, from: date, to: self);
let seconds = "\(difference.second ?? 0)s"
let minutes = "\(difference.minute ?? 0)m" + " " + seconds
let hours = "\(difference.hour ?? 0)h" + " " + minutes
let days = "\(difference.day ?? 0)d" + " " + hours
if let day = difference.day, day > 0 { return days }
if let hour = difference.hour, hour > 0 { return hours }
if let minute = difference.minute, minute > 0 { return minutes }
if let second = difference.second, second > 0 { return seconds }
return ""
}
}
Upvotes: 3
Reputation: 731
private func calculateDaysBetweenTwoDates(start: Date, end: Date) -> Int {
let currentCalendar = Calendar.current
guard let start = currentCalendar.ordinality(of: .day, in: .era, for: start) else {
return 0
}
guard let end = currentCalendar.ordinality(of: .day, in: .era, for: end) else {
return 0
}
return end - start
}
Upvotes: 9
Reputation: 911
Swift 4 Version
let startDate = "2000-11-22"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let formatedStartDate = dateFormatter.date(from: startDate)
let currentDate = Date()
let components = Set<Calendar.Component>([.second, .minute, .hour, .day, .month, .year])
let differenceOfDate = Calendar.current.dateComponents(components, from: formatedStartDate!, to: currentDate)
print (differenceOfDate)
Printed - year: 16 month: 10 day: 19 hour: 12 minute: 16 second: 42 isLeapMonth: false
Upvotes: 23
Reputation: 1147
In Swift4 we can easily get no of days between two different calendar dates using below codes.
First one is the difference in days with the current date.
let previousDate = "2017-03-01"
let currentDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let previousDateFormated : Date? = dateFormatter.date(from: previousDate)
let difference = currentDate.timeIntervalSince(previousDateFormated!)
var differenceInDays = Int(difference/(60 * 60 * 24 ))
print(differenceInDays)
Continuing with the above code ... Below is for finding no of days for two different dates. the content of previous date is taken from above date
let futureDate = "2017-12-30"
let futureDateFormatted : Date? = dateFormatter.date(from: futureDate)
differenceInDays = (futureDateFormatted?.timeIntervalSince(previousDateFormated!))! / (60 * 60 * 24)
print(differenceInDays)
Upvotes: 7
Reputation: 3317
Updated for Swift 3:
if you want to print the number of days as well as days list between two calendar dates, used below simple code;
// Variable Declaration:
var daysListArray = [String]()
// function Defination:
func printCountBtnTwoDates(mStartDate: Date, mEndDate: Date) -> Int {
let calendar = Calendar.current
let formatter = DateFormatter()
var newDate = mStartDate
daysListArray.removeAll()
while newDate <= mEndDate {
formatter.dateFormat = "yyyy-MM-dd"
daysListArray.append(formatter.string(from: newDate))
newDate = calendar.date(byAdding: .day, value: 1, to: newDate)!
}
// print("daysListArray: \(daysListArray)") // if you want to print list between start date and end date
return daysListArray.count
}
// To call above function:
let count = self.printCountBtnTwoDates(mStartDate: your_start_date, mEndDate: your_end_date)
print("count: \(count)") // date count
// Enjoy coding...!
Upvotes: 0
Reputation: 5891
Turns out this is much simpler to do in Swift 3:
extension Date {
func interval(ofComponent comp: Calendar.Component, fromDate date: Date) -> Int {
let currentCalendar = Calendar.current
guard let start = currentCalendar.ordinality(of: comp, in: .era, for: date) else { return 0 }
guard let end = currentCalendar.ordinality(of: comp, in: .era, for: self) else { return 0 }
return end - start
}
}
Edit
Comparing the ordinality of the two dates should be within the same era
instead of the same year
, since naturally the two dates may fall in different years.
Usage
let yesterday = Date(timeInterval: -86400, since: Date())
let tomorrow = Date(timeInterval: 86400, since: Date())
let diff = tomorrow.interval(ofComponent: .day, fromDate: yesterday)
// return 2
Upvotes: 60