Vinod Vishwanath
Vinod Vishwanath

Reputation: 5891

Swift 3 - find number of calendar days between two dates

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

Answers (10)

Coltuxumab
Coltuxumab

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

Anuj Panwar
Anuj Panwar

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

flo_23
flo_23

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

Mohammad Razipour
Mohammad Razipour

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

Meet Doshi
Meet Doshi

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

Kevin
Kevin

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

Steve B
Steve B

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

Ashim Dahal
Ashim Dahal

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

Kiran Jadhav
Kiran Jadhav

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

Vinod Vishwanath
Vinod Vishwanath

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

Related Questions