ixany
ixany

Reputation: 6040

All dates between two Date objects (Swift)

I’m creating a date using NSDateComponents().

let startDate = NSDateComponents()
startDate.year = 2015
startDate.month = 9
startDate.day = 1
let calendar = NSCalendar.currentCalendar()
let startDateNSDate = calendar.dateFromComponents(startDate)!

... now I want to print all dates since the startDate until today, NSDate(). I’ve already tried playing with NSCalendarUnit, but it only outputs the whole difference, not the single dates between.

let unit: NSCalendarUnit = [.Year, .Month, .Day, .Hour, .Minute, .Second]
let diff = NSCalendar.currentCalendar().components(unit, fromDate: startDateNSDate, toDate: NSDate(), options: [])

How can I print all dates between two Dateobjects?

Edit 2019

In the meantime the naming of the classes had changed – NSDate is now just Date. NSDateComponents is now called DateComponents. NSCalendar.currentCalendar() is now just Calendar.current.

Upvotes: 50

Views: 34744

Answers (8)

Sergey Sergeyev
Sergey Sergeyev

Reputation: 844

let easy = DateInterval(start: date1, end: date2).days

let extended = Calendar.current.dateInterval(year: 2025, month: 5).days
extension DateInterval {

var days: [Date] {
    let calendar = Calendar.current
    let days = calendar.dateComponents([.day], from: start, to: end).day ?? 0
    return Array(0...days).compactMap {
        calendar.date(byAdding: .day, value: $0, to: start)
    }
}}
Please add to the current implementation of the function, how to write it better, perhaps:
extension Calendar {

func dateInterval(year: Int, month: Int?, extendedToWeek: Bool = false) -> DateInterval? {
    guard
        var start = date(from: DateComponents(year: year, month: month)),
        var interval = dateInterval(of: month != nil ? .month : .year, for: start),
        var end = date(byAdding: .day, value: -1, to: interval.end)
    else { return nil }
    
    if extendedToWeek {
        let component: Calendar.Component = month != nil ? .weekOfMonth : .weekOfYear
        start = dateInterval(of: component, for: start)?.start ?? start
        interval = dateInterval(of: component, for: end) ?? interval
        end = date(byAdding: .day, value: -1, to: interval.end) ?? end
    }
    return DateInterval(start: start, end: end)
}}
Interval aligned to weeks for a simple calendar. (extendedToWeek:)

Interval aligned to weeks for a simple calendar. (extendedToWeek:)

Upvotes: 2

dwaz
dwaz

Reputation: 664

You can use the compactMap operator. I like to put these functions in an extension so they are reusable. It's hard to make a range of dates, so I made a range of ints and loop through that.

extension Calendar {
    func getDates(_ startDate: Date, _ endDate: Date) -> [Date]  {
        // make sure parameters are valid
        guard startDate < endDate else { print("invalid parameters"); return [] }
        // how many days between dates?
        let dayDiff = Int(self.dateComponents([.day], from: startDate, to: endDate).day ?? 0)
        let rangeOfDaysFromStart: Range<Int> = 0..<dayDiff + 1
        let dates = rangeOfDaysFromStart.compactMap{ self.date(byAdding: .day, value: $0, to: startDate) }
        return dates
    }
}

Your usage could be:

let startDate = Date(dateString: "1/2/2017", format: "M/d/yyyy")
let endDate = Date(dateString: "1/9/2017", format: "M/d/yyyy")
let dates = Calendar.current.getDates(startDate, endDate)
let f = DateFormatter(withFormat: "yyyy-MM-dd", locale: "us_en")
print(dates.compactMap{f.string(from: $0)}.joined(separator: ", "))

output:

"2017-01-02, 2017-01-03, 2017-01-04, 2017-01-05, 2017-01-06, 2017-01-07, 2017-01-08, 2017-01-09"

Upvotes: 3

Alvin George
Alvin George

Reputation: 14296

Using extension:

extension Date {
    static func dates(from fromDate: Date, to toDate: Date) -> [Date] {
        var dates: [Date] = []
        var date = fromDate
        
        while date <= toDate {
            dates.append(date)
            guard let newDate = Calendar.current.date(byAdding: .day, value: 1, to: date) else { break }
            date = newDate
        }
        return dates
    }
}

Usage:

let datesBetweenArray = Date.dates(from: Date(), to: Date())

Upvotes: 52

Nikunj Kumbhani
Nikunj Kumbhani

Reputation: 3924

Here is Solution of Print all dates between two Dates (Swift 4 Code)

var mydates : [String] = []
var dateFrom =  Date() // First date
var dateTo = Date()   // Last date

// Formatter for printing the date, adjust it according to your needs:
let fmt = DateFormatter()
fmt.dateFormat = "yyy-MM-dd"
dateFrom = fmt.date(from: strstartDate)! // "2018-03-01"
dateTo = fmt.date(from: strendDate)! // "2018-03-05"


while dateFrom <= dateTo {
    mydates.append(fmt.string(from: dateFrom))
    dateFrom = Calendar.current.date(byAdding: .day, value: 1, to: dateFrom)!

}

print(mydates) // Your Result

Output is:

["2018-03-01", "2018-03-02", "2018-03-03", "2018-03-04", "2018-03-05"]

Upvotes: 5

Martin R
Martin R

Reputation: 539685

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)!
}

Upvotes: 71

AlexanderZ
AlexanderZ

Reputation: 2158

Same thing but prettier:

extension Date {

  func allDates(till endDate: Date) -> [Date] {
    var date = self
    var array: [Date] = []
    while date <= endDate {
      array.append(date)
      date = Calendar.current.date(byAdding: .day, value: 1, to: date)!
    }
    return array
  }
}

How to get all dates for next 20 days:

if let date = Calendar.current.date(byAdding: .day, value: 20, to: Date()) {
  print(Date().allDates(till: date))
}

Upvotes: 10

Stefan Ciprian Hotoleanu
Stefan Ciprian Hotoleanu

Reputation: 2292

I am using this approach (Swift 3):

import Foundation

class Dates {
    static func printDatesBetweenInterval(_ startDate: Date, _ endDate: Date) {
        var startDate = startDate
        let calendar = Calendar.current

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

        while startDate <= endDate {
            print(fmt.string(from: startDate))
            startDate = calendar.date(byAdding: .day, value: 1, to: startDate)!
        }
    }

    static func dateFromString(_ dateString: String) -> Date {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"

        return dateFormatter.date(from: dateString)!
    }
}

and I am calling this like:

Dates.printDatesBetweenInterval(Dates.dateFromString("2017-01-02"), Dates.dateFromString("2017-01-9"))

The output is:

2017-01-02
2017-01-03
2017-01-04
2017-01-05
2017-01-06
2017-01-07
2017-01-08
2017-01-09

Upvotes: 2

M.Shuaib Imran
M.Shuaib Imran

Reputation: 1307

Your desired code becomes like

    let startDate = NSDateComponents()
    startDate.year = 2015
    startDate.month = 9
    startDate.day = 1
    let calendar = NSCalendar.currentCalendar()
    let startDateNSDate = calendar.dateFromComponents(startDate)!


    var offsetComponents:NSDateComponents = NSDateComponents();
    offsetComponents.day = 1
    var nd:NSDate = startDateNSDate;

    println(nd)
    while nd.timeIntervalSince1970 < NSDate().timeIntervalSince1970 {
        nd = calendar.dateByAddingComponents(offsetComponents, toDate: nd, options: nil)!;
            println(nd)


    }

Upvotes: 3

Related Questions