Swift days between two NSDates

IosSwiftDateDate Difference

Ios Problem Overview


I'm wondering if there is some new and awesome possibility to get the amount of days between two NSDates in Swift / the "new" Cocoa?

E.g. like in Ruby I would do:

(end_date - start_date).to_i

Ios Solutions


Solution 1 - Ios

You have to consider the time difference as well. For example if you compare the dates 2015-01-01 10:00 and 2015-01-02 09:00, days between those dates will return as 0 (zero) since the difference between those dates is less than 24 hours (it's 23 hours).

If your purpose is to get the exact day number between two dates, you can work around this issue like this:

// Assuming that firstDate and secondDate are defined
// ...

let calendar = NSCalendar.currentCalendar()

// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDayForDate(firstDate)
let date2 = calendar.startOfDayForDate(secondDate)

let flags = NSCalendarUnit.Day
let components = calendar.components(flags, fromDate: date1, toDate: date2, options: [])

components.day  // This will return the number of day(s) between dates

Swift 3 and Swift 4 Version

let calendar = Calendar.current
    
// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDay(for: firstDate)
let date2 = calendar.startOfDay(for: secondDate)
   
let components = calendar.dateComponents([.day], from: date1, to: date2)

Solution 2 - Ios

Here is my answer for Swift 2:

func daysBetweenDates(startDate: NSDate, endDate: NSDate) -> Int
{
    let calendar = NSCalendar.currentCalendar()

    let components = calendar.components([.Day], fromDate: startDate, toDate: endDate, options: [])

    return components.day
}

Solution 3 - Ios

I see a couple Swift3 answers so I'll add my own:

public static func daysBetween(start: Date, end: Date) -> Int {
   Calendar.current.dateComponents([.day], from: start, to: end).day!
}

The naming feels more Swifty, it's one line, and using the latest dateComponents() method.

Solution 4 - Ios

Here is very nice, Date extension to get difference between dates in years, months, days, hours, minutes, seconds

extension Date {
    
    func years(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.year], from: sinceDate, to: self).year
    }
    
    func months(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.month], from: sinceDate, to: self).month
    }
    
    func days(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.day], from: sinceDate, to: self).day
    }
    
    func hours(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.hour], from: sinceDate, to: self).hour
    }
    
    func minutes(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.minute], from: sinceDate, to: self).minute
    }
    
    func seconds(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.second], from: sinceDate, to: self).second
    }
   
}

Solution 5 - Ios

I translated my Objective-C answer

let start = "2010-09-01"
let end = "2010-09-05"

let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"

let startDate:NSDate = dateFormatter.dateFromString(start)
let endDate:NSDate = dateFormatter.dateFromString(end)

let cal = NSCalendar.currentCalendar()


let unit:NSCalendarUnit = .Day

let components = cal.components(unit, fromDate: startDate, toDate: endDate, options: nil)


println(components)

result

<NSDateComponents: 0x10280a8a0>
     Day: 4

The hardest part was that the autocompletion insists fromDate and toDate would be NSDate?, but indeed they must be NSDate! as shown in the reference.

I don't see how a good solution with an operator would look like, as you want to specify the unit differently in each case. You could return the time interval, but than won't you gain much.

Solution 6 - Ios

Update for Swift 3 iOS 10 Beta 4

func daysBetweenDates(startDate: Date, endDate: Date) -> Int {
    let calendar = Calendar.current
    let components = calendar.dateComponents([Calendar.Component.day], from: startDate, to: endDate)
    return components.day!
}

Solution 7 - Ios

Swift 5. Thanks to [Emin Buğra Saral][1] above for the startOfDay suggestion.

extension Date {
    
    func daysBetween(date: Date) -> Int {
        return Date.daysBetween(start: self, end: date)
    }
    
    static func daysBetween(start: Date, end: Date) -> Int {
        let calendar = Calendar.current
        
        // Replace the hour (time) of both dates with 00:00
        let date1 = calendar.startOfDay(for: start)
        let date2 = calendar.startOfDay(for: end)
        
        let a = calendar.dateComponents([.day], from: date1, to: date2)
        return a.value(for: .day)!
    }
}

Usage:

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let start = dateFormatter.date(from: "2017-01-01")!
let end = dateFormatter.date(from: "2018-01-01")!

let diff = Date.daysBetween(start: start, end: end) // 365
// or
let diff = start.daysBetween(date: end) // 365

[1]: https://stackoverflow.com/users/1437254/emin-bu%C4%9Fra-saral/ "Emin"

Solution 8 - Ios

Here is the answer for Swift 3 (tested for IOS 10 Beta)

func daysBetweenDates(startDate: Date, endDate: Date) -> Int
{
    let calendar = Calendar.current
    let components = calendar.components([.day], from: startDate, to: endDate, options: [])
    return components.day!
}

Then you can call it like this

let pickedDate: Date = sender.date
let NumOfDays: Int = daysBetweenDates(startDate: pickedDate, endDate: Date())
    print("Num of Days: \(NumOfDays)")

Solution 9 - Ios

Swift 5

Working, you need to set the time to be the same for both days, if you are off by seconds it will be wrong

func daysBetween(start: Date, end: Date) -> Int {
    let start = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: start)!
    let end = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: end)!
    return Calendar.current.dateComponents([.day], from: start, to: end).day ?? 0
}

Solution 10 - Ios

The things built into swift are still very basic. As they should be at this early stage. But you can add your own stuff with the risk that comes with overloading operators and global domain functions. They will be local to your module though.

let now = NSDate()
let seventies = NSDate(timeIntervalSince1970: 0)

// Standard solution still works
let days = NSCalendar.currentCalendar().components(.CalendarUnitDay, 
           fromDate: seventies, toDate: now, options: nil).day

// Flashy swift... maybe...
func -(lhs:NSDate, rhs:NSDate) -> DateRange {
    return DateRange(startDate: rhs, endDate: lhs)
}

class DateRange {
    let startDate:NSDate
    let endDate:NSDate
    var calendar = NSCalendar.currentCalendar()
    var days: Int {
        return calendar.components(.CalendarUnitDay, 
               fromDate: startDate, toDate: endDate, options: nil).day
    }
    var months: Int {
        return calendar.components(.CalendarUnitMonth, 
               fromDate: startDate, toDate: endDate, options: nil).month
    }
    init(startDate:NSDate, endDate:NSDate) {
        self.startDate = startDate
        self.endDate = endDate
    }
}

// Now you can do this...
(now - seventies).months
(now - seventies).days

Solution 11 - Ios

This is an updated version of Emin's answer for Swift 5 that incorporates the suggestion to use noon instead of midnight as the definitive time for comparing days. It also handles the potential failure of various date functions by returning an optional.

///
/// This is an approximation; it does not account for time differences. It will set the time to 1200 (noon) and provide the absolute number
/// of days between now and the given date. If the result is negative, it should be read as "days ago" instead of "days from today."
/// Returns nil if something goes wrong initializing or adjusting dates.
///

func daysFromToday() -> Int?
{
    let calendar = NSCalendar.current

    // Replace the hour (time) of both dates with noon. (Noon is less likely to be affected by DST changes, timezones, etc. than midnight.)
    guard let date1 = calendar.date(bySettingHour: 12, minute: 00, second: 00, of: calendar.startOfDay(for: Date())),
          let date2 = calendar.date(bySettingHour: 12, minute: 00, second: 00, of: calendar.startOfDay(for: self)) else
    {
        return nil
    }
    
    return calendar.dateComponents([.day], from: date1, to: date2).day
}

Solution 12 - Ios

Here is my answer for Swift 3:

func daysBetweenDates(startDate: NSDate, endDate: NSDate, inTimeZone timeZone: TimeZone? = nil) -> Int {
    var calendar = Calendar.current
    if let timeZone = timeZone {
        calendar.timeZone = timeZone
    }
    let dateComponents = calendar.dateComponents([.day], from: startDate.startOfDay, to: endDate.startOfDay)
    return dateComponents.day!
}

Solution 13 - Ios

You could use the following extension:

public extension Date {
    func daysTo(_ date: Date) -> Int? {
        let calendar = Calendar.current

        // Replace the hour (time) of both dates with 00:00
        let date1 = calendar.startOfDay(for: self)
        let date2 = calendar.startOfDay(for: date)
    
        let components = calendar.dateComponents([.day], from: date1, to: date2)
        return components.day  // This will return the number of day(s) between dates
    }
}

Then, you can call it like this:

startDate.daysTo(endDate)

Solution 14 - Ios

There's hardly any Swift-specific standard library yet; just the lean basic numeric, string, and collection types.

It's perfectly possible to define such shorthands using extensions, but as far as the actual out-of-the-box APIs goes, there is no "new" Cocoa; Swift just maps directly to the same old verbose Cocoa APIs as they already exist.

Solution 15 - Ios

I'm going to add my version even though this thread is a year old. My code looks like this:

    var name = txtName.stringValue // Get the users name
    
    // Get the date components from the window controls
    var dateComponents = NSDateComponents()
    dateComponents.day = txtDOBDay.integerValue
    dateComponents.month = txtDOBMonth.integerValue
    dateComponents.year = txtDOBYear.integerValue
    
    // Make a Gregorian calendar
    let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
    
    // Get the two dates we need
    var birthdate = calendar?.dateFromComponents(dateComponents)
    let currentDate = NSDate()
    
    var durationDateComponents = calendar?.components(NSCalendarUnit.CalendarUnitDay, fromDate: birthdate!, toDate: currentDate, options: nil)
    
    let numberOfDaysAlive = durationDateComponents?.day
    
    println("\(numberOfDaysAlive!)")
    
    txtGreeting.stringValue = "Hello \(name), You have been alive for \(numberOfDaysAlive!) days."

I hope it helps someone.

Cheers,

Solution 16 - Ios

Erin's method updated to Swift 3, This shows days from today (disregarding time of day)

func daysBetweenDates( endDate: Date) -> Int 
    let calendar: Calendar = Calendar.current 
    let date1 = calendar.startOfDay(for: Date()) 
    let date2 = calendar.startOfDay(for: secondDate) 
    return calendar.dateComponents([.day], from: date1, to: date2).day! 
}

Solution 17 - Ios

This returns an absolute difference in days between some Date and today:

extension Date {
  func daysFromToday() -> Int {
    return abs(Calendar.current.dateComponents([.day], from: self, to: Date()).day!)
  }
}

and then use it:

if someDate.daysFromToday() >= 7 {
  // at least a week from today
}

Solution 18 - Ios

easier option would be to create a extension on Date

public extension Date {
        
        public var currentCalendar: Calendar {
            return Calendar.autoupdatingCurrent
        }
        
        public func daysBetween(_ date: Date) -> Int {
            let components = currentCalendar.dateComponents([.day], from: self, to: date)
            return components.day!
        }
    }

Solution 19 - Ios

Swift 3.2

extension DateComponentsFormatter {
    func difference(from fromDate: Date, to toDate: Date) -> String? {
        self.allowedUnits = [.year,.month,.weekOfMonth,.day]
        self.maximumUnitCount = 1
        self.unitsStyle = .full
        return self.string(from: fromDate, to: toDate)
    }
}

Solution 20 - Ios

All answer is good. But for Localizations we need calculates a number of decimal days in between two dates. so we can provide the sustainable decimal format.

// This method returns the fractional number of days between to dates
func getFractionalDaysBetweenDates(date1: Date, date2: Date) -> Double {
    
    let components = Calendar.current.dateComponents([.day, .hour], from: date1, to: date2)
    
    var decimalDays = Double(components.day!)
    decimalDays += Double(components.hour!) / 24.0
    
    return decimalDays
}

Solution 21 - Ios

Nice handy one liner :

extension Date {
  var daysFromNow: Int {
    return Calendar.current.dateComponents([.day], from: Date(), to: self).day!
  }
}

Solution 22 - Ios

Swift 3 - Days from today until date

func daysUntilDate(endDateComponents: DateComponents) -> Int
    {
        let cal = Calendar.current
        var components = cal.dateComponents([.era, .year, .month, .day], from: NSDate() as Date)
        let today = cal.date(from: components)
        let otherDate = cal.date(from: endDateComponents)
        
        components = cal.dateComponents([Calendar.Component.day], from: (today! as Date), to: otherDate!)
        return components.day!
    }

Call function like this

// Days from today until date
   var examnDate = DateComponents()
   examnDate.year = 2016
   examnDate.month = 12
   examnDate.day = 15
   let daysCount = daysUntilDate(endDateComponents: examnDate)

Solution 23 - Ios

  func completeOffset(from date:Date) -> String? {
    
    let formatter = DateComponentsFormatter()
    formatter.unitsStyle = .brief
    
    return  formatter.string(from: Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second], from: date, to: self))
    
    
    
    
}

if you need year month days and hours as string use this

var tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date())!

let dc = tomorrow.completeOffset(from: Date())

Solution 24 - Ios

extension Date {
    func daysFromToday() -> Int {
        return Calendar.current.dateComponents([.day], from: self, to: Date()).day!
    }
}

Then use it like

    func dayCount(dateString: String) -> String{
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMM dd,yyyy hh:mm a"
        let fetchedDate = dateFormatter.date(from: dateString)
    
    
        let day = fetchedDate?.daysFromToday()
        if day! > -1{
            return "\(day!) days passed."
        }else{
        return "\(day! * -1) days left."
        }
    }

Solution 25 - Ios

extension Date {
static func - (recent: Date, previous: Date) -> DateComponents {
    var dateComponents = DateComponents()
    dateComponents.year = Calendar.current.dateComponents([.day], from: previous, to: recent).year
    dateComponents.month = Calendar.current.dateComponents([.month], from: previous, to: recent).month
    dateComponents.day = Calendar.current.dateComponents([.day], from: previous, to: recent).day
    dateComponents.hour = Calendar.current.dateComponents([.hour], from: previous, to: recent).hour
    dateComponents.minute = Calendar.current.dateComponents([.minute], from: previous, to: recent).minute
    dateComponents.second = Calendar.current.dateComponents([.second], from: previous, to: recent).second
    return dateComponents
   }
}

Solution 26 - Ios

2017 version, copy and paste

func simpleIndex(ofDate: Date) -> Int {
    
    // index here just means today 0, yesterday -1, tomorrow 1 etc.
    
    let c = Calendar.current
    let todayRightNow = Date()
    
    let d = c.date(bySetting: .hour, value: 13, of: ofDate)
    let t = c.date(bySetting: .hour, value: 13, of: todayRightNow)
    
    if d == nil || today == nil {
    
        print("weird problem simpleIndex#ofDate")
        return 0
    }
    
    let r = c.dateComponents([.day], from: today!, to: d!)
    // yesterday is negative one, tomorrow is one
    
    if let o = r.value(for: .day) {
        
        return o
    }
    else {
    
        print("another weird problem simpleIndex#ofDate")
        return 0
    }
}

Solution 27 - Ios

let calendar = NSCalendar.currentCalendar();
let component1 = calendar.component(.Day, fromDate: fromDate)
let component2 = calendar.component(.Day, fromDate: toDate)
let difference  = component1 - component2

Solution 28 - Ios

Swift 5.2.4 solution:

import UIKit

let calendar = Calendar.current

let start = "2010-09-01"
let end = "2010-09-05"

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"

let firstDate = dateFormatter.date(from: start)!
let secondDate = dateFormatter.date(from: end)!

// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDay(for: firstDate)
let date2 = calendar.startOfDay(for: secondDate)

let components = calendar.dateComponents([Calendar.Component.day], from: date1, to: date2)

components.day  // This will return the number of day(s) between dates

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLinusView Question on Stackoverflow
Solution 1 - IosEmin Bugra SaralView Answer on Stackoverflow
Solution 2 - IosiphaawView Answer on Stackoverflow
Solution 3 - IostelkinsView Answer on Stackoverflow
Solution 4 - IosKrunalView Answer on Stackoverflow
Solution 5 - IosvikingosegundoView Answer on Stackoverflow
Solution 6 - IosChaosSpeederView Answer on Stackoverflow
Solution 7 - IosNormanView Answer on Stackoverflow
Solution 8 - IoskazantatarView Answer on Stackoverflow
Solution 9 - IosMike ZrielView Answer on Stackoverflow
Solution 10 - IosDaniel SchlaugView Answer on Stackoverflow
Solution 11 - IosBryanView Answer on Stackoverflow
Solution 12 - IosAlen LiangView Answer on Stackoverflow
Solution 13 - IosMauro GarcíaView Answer on Stackoverflow
Solution 14 - IosWes CampaigneView Answer on Stackoverflow
Solution 15 - IosAndrew HView Answer on Stackoverflow
Solution 16 - IosPeter JohnsonView Answer on Stackoverflow
Solution 17 - IosbudiDinoView Answer on Stackoverflow
Solution 18 - IosSuhit PatilView Answer on Stackoverflow
Solution 19 - IosAdam SmakaView Answer on Stackoverflow
Solution 20 - IosDurul DalkanatView Answer on Stackoverflow
Solution 21 - IosRom.View Answer on Stackoverflow
Solution 22 - IosdianakarenmsView Answer on Stackoverflow
Solution 23 - IosAkash ShindheView Answer on Stackoverflow
Solution 24 - IosMurad Al WajedView Answer on Stackoverflow
Solution 25 - IosraeesView Answer on Stackoverflow
Solution 26 - IosFattieView Answer on Stackoverflow
Solution 27 - IosRaj AggrawalView Answer on Stackoverflow
Solution 28 - IosmazyView Answer on Stackoverflow