Getting the difference between two Dates (months/days/hours/minutes/seconds) in Swift
Xcode 8.3 • Swift 3.1 or later
You can use Calendar to help you create an extension to do your date calculations as follow:
extension Date {
/// Returns the amount of years from another date
func years(from date: Date) -> Int {
return Calendar.current.dateComponents([.year], from: date, to: self).year ?? 0
}
/// Returns the amount of months from another date
func months(from date: Date) -> Int {
return Calendar.current.dateComponents([.month], from: date, to: self).month ?? 0
}
/// Returns the amount of weeks from another date
func weeks(from date: Date) -> Int {
return Calendar.current.dateComponents([.weekOfMonth], from: date, to: self).weekOfMonth ?? 0
}
/// Returns the amount of days from another date
func days(from date: Date) -> Int {
return Calendar.current.dateComponents([.day], from: date, to: self).day ?? 0
}
/// Returns the amount of hours from another date
func hours(from date: Date) -> Int {
return Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0
}
/// Returns the amount of minutes from another date
func minutes(from date: Date) -> Int {
return Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0
}
/// Returns the amount of seconds from another date
func seconds(from date: Date) -> Int {
return Calendar.current.dateComponents([.second], from: date, to: self).second ?? 0
}
/// Returns the a custom time interval description from another date
func offset(from date: Date) -> String {
if years(from: date) > 0 { return "\(years(from: date))y" }
if months(from: date) > 0 { return "\(months(from: date))M" }
if weeks(from: date) > 0 { return "\(weeks(from: date))w" }
if days(from: date) > 0 { return "\(days(from: date))d" }
if hours(from: date) > 0 { return "\(hours(from: date))h" }
if minutes(from: date) > 0 { return "\(minutes(from: date))m" }
if seconds(from: date) > 0 { return "\(seconds(from: date))s" }
return ""
}
}
Using Date Components Formatter
let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.allowedUnits = [.second, .minute, .hour, .day, .weekOfMonth, .month, .year]
dateComponentsFormatter.maximumUnitCount = 1
dateComponentsFormatter.unitsStyle = .full
dateComponentsFormatter.string(from: Date(), to: Date(timeIntervalSinceNow: 4000000)) // "1 month"
let date1 = DateComponents(calendar: .current, year: 2014, month: 11, day: 28, hour: 5, minute: 9).date!
let date2 = DateComponents(calendar: .current, year: 2015, month: 8, day: 28, hour: 5, minute: 9).date!
let years = date2.years(from: date1) // 0
let months = date2.months(from: date1) // 9
let weeks = date2.weeks(from: date1) // 39
let days = date2.days(from: date1) // 273
let hours = date2.hours(from: date1) // 6,553
let minutes = date2.minutes(from: date1) // 393,180
let seconds = date2.seconds(from: date1) // 23,590,800
let timeOffset = date2.offset(from: date1) // "9M"
let date3 = DateComponents(calendar: .current, year: 2014, month: 11, day: 28, hour: 5, minute: 9).date!
let date4 = DateComponents(calendar: .current, year: 2015, month: 11, day: 28, hour: 5, minute: 9).date!
let timeOffset2 = date4.offset(from: date3) // "1y"
let date5 = DateComponents(calendar: .current, year: 2017, month: 4, day: 28).date!
let now = Date()
let timeOffset3 = now.offset(from: date5) // "1w"
Calculate duration between date ios in Years, months and date format
If you need the difference (in years, months, days) numerically then
compute NSDateComponents
as in Swift days between two NSDates or Rajan's answer.
If you need the difference as a (localized) string to present it to the user,
then use NSDateComponentsFormatter
like this
let form = NSDateComponentsFormatter()
form.maximumUnitCount = 2
form.unitsStyle = .Full
form.allowedUnits = [.Year, .Month, .Day]
let s = form.stringFromDate(date1, toDate: date2)
As already mentioned in the comments, computing the difference
from the pure time interval between the dates cannot give correct
results because most information about the dates is lost.
Update for Swift 3:
let form = DateComponentsFormatter()
form.maximumUnitCount = 2
form.unitsStyle = .full
form.allowedUnits = [.year, .month, .day]
let s = form.string(from: date1, to: date2)
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.
Getting the difference in two dates - Swift
Change all of your NSDate
to Date
, then replace your requestedComponent
with this:
let requestedComponent: Set<Calendar.Component> = [ .month, .day, .hour, .minute, .second]
Your difference will be:
let timeDifference = userCalendar.dateComponents(requestedComponent, from: startTime, to: endTime!)
FYI: Your dateFormatter
doesn't work with this "25/12/16 00:00:00"
here is your whole class in correct form:
class ViewController: UIViewController {
@IBOutlet weak var dateLabelOutlet: UILabel!
let currentDate = Date()
let dateFormatter = DateFormatter()
let userCalendar = Calendar.current
let requestedComponent: Set<Calendar.Component> = [.month,.day,.hour,.minute,.second]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func printTime() {
dateFormatter.dateFormat = "dd/MM/yy hh:mm:ss"
let startTime = Date()
let endTime = dateFormatter.date(from: "25/12/16 00:00:00")
let timeDifference = userCalendar.dateComponents(requestedComponent, from: startTime, to: endTime!)
dateLabelOutlet.text = "\(timeDifference.month) Months \(timeDifference.day) Days \(timeDifference.minute) Minutes \(timeDifference.second) Seconds"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Swift 3 - find number of calendar days between two dates
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
All dates between two Date objects (Swift)
Just add one day unit to the date until it reaches
the current date (Swift 2 code):
var date = startDateNSDate // first date
let endDate = NSDate() // last date
// Formatter for printing the date, adjust it according to your needs:
let fmt = NSDateFormatter()
fmt.dateFormat = "dd/MM/yyyy"
// While date <= endDate ...
while date.compare(endDate) != .OrderedDescending {
print(fmt.stringFromDate(date))
// Advance by one day:
date = calendar.dateByAddingUnit(.Day, value: 1, toDate: date, options: [])!
}
Update for Swift 3:
var date = startDate // first date
let endDate = Date() // last date
// Formatter for printing the date, adjust it according to your needs:
let fmt = DateFormatter()
fmt.dateFormat = "dd/MM/yyyy"
while date <= endDate {
print(fmt.string(from: date))
date = Calendar.current.date(byAdding: .day, value: 1, to: date)!
}
Difference between 2 dates in weeks and days using swift 3 and xcode 8
You can use Calendar
's dateComponents(_:from:to:)
to find the difference between 2 dates to your desired units.
Example:
let dateRangeStart = Date()
let dateRangeEnd = Date().addingTimeInterval(12345678)
let components = Calendar.current.dateComponents([.weekOfYear, .month], from: dateRangeStart, to: dateRangeEnd)
print(dateRangeStart)
print(dateRangeEnd)
print("difference is \(components.month ?? 0) months and \(components.weekOfYear ?? 0) weeks")
> 2017-02-17 10:05:19 +0000
> 2017-07-10 07:26:37 +0000
> difference is 4 months and 3 weeks
let months = components.month ?? 0
let weeks = components.weekOfYear ?? 0
Calculating the number of days between two dates in swift
It has to do with the order that you're creating your variables and comparing them.
The first thing you do is create today
. Then, you create twoWeeksFromNow
, based on a new Date()
that will be slightly further in the future than today
was. On my machine, in a playground, the second date is about 300 microseconds further in the future than the first.
Then, for numDaysWithDate
, you compare twoWeeksFromNow
to another new Date()
, even more slightly in the future. So, your time frame is very slightly less than 2 full weeks, giving you 13 days.
But, for numDaysWithToday
, you compare twoWeeksFromNow
with the original today
, which was created before twoWeeksFromNow
was, making it slightly longer than 2 weeks, giving you 14 days.
If you change the order of the the today
and twoWeeksFromNow
declarations, you can see a different result:
var twoWeeksFromNow: Date = Calendar.current.date(byAdding: .day,
value: 14, to: Date())!
var today = Date()
Now, because today
was created slightly later than the date that twoWeeksFromNow
was created from, both results are 13.
How to determine date falls in between two dates swift
If you have Date objects, they are Comparable and Equatable. You can write code like:
if breakDate >= startDate && breakDate <= endDate {
// breakDate is between startDate and endDate
}
Edit:
As pointed out by LeoDabus in the comments, you could also use the pattern match operator (although I personally don't like it)
if startDate ... endDate ~= breakDate {
// breakDate is between startDate and endDate
}
or contains:
if (startDate...endDate).contains(breakDate) {
// breakDate is between startDate and endDate
}
If you have date strings, create a date formatter that converts your date strings to Date
objects, then use code like the above.
If the date strings are always in "Internet" date format (ISO 8601), and you are certain they will always be in the same time zone, you can also use string comparison and compare the date strings directly (using any of the above forms of comparison, except maybe contains?)
Related Topics
Pausing Timer When App Is in Background State Swift
How to Create an Image of Specific Size from Uiview
Video with Gpuimagechromakeyfilter Has Tint When Played in Transparent Gpuimageview
Coredata Conditionally Fetching on Nsdate Using Nspredicate (Swift)
Uicollectionview Cells with Images Inside Uitableview Prototype
Uitextview - Adjust Size Based on the Content in Swiftui
Please Add the Host Targets for the Embedded Targets to the Podfile
How to Catch Nsunknownkeyexception in Swift 2.2
Adding Firebase Data to an Array in iOS Swift
Expand Uitextview and Uitableview When Uitextview's Text Extends Beyond 1 Line
How to Change How a Remote Notification Is Presented Before Presentation
Programmatically Obtaining the Imei or Udid of an iOS Device
Which Passes How to Access in Apple Wallet
iOS Development App Startup Crash
How to Use Alamofires Servertrustpolicy.Disableevaluation in Swift 3