UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

getting the difference between two dates in swiftui

Forums > 100 Days of SwiftUI

In SwiftUI, all I'm looking to do is get the difference between two dates -- as in, 'here is the current date' and 'here is August 5th, 1992' for example, and therefore the number of days, months, years, between those two dates is x number of days, x number of months, and x number of years.

This seems relatively straightforward, and yet I can't find any reasonable way to get an accurate answer. I can output dates like the two below, but I can't figure out how to get the difference between them. Is there a simple-ish solution?

2017-08-06 19:20:42 +0000

2020-08-06 19:20:46 +0000

2      

Use Calendar.dateComponents(_:from:to:), like so:

import Foundation

let fmt = ISO8601DateFormatter()

let date1 = fmt.date(from: "2017-08-06T19:20:42+0000")!
let date2 = fmt.date(from: "2020-08-06T19:20:46+0000")!

let diffs = Calendar.current.dateComponents([.year, .month, .day], from: date1, to: date2)
print(diffs)

The result of this code is:

year: 3 month: 0 day: 0 isLeapMonth: false

5      

this is excellent, thank you. I was able to arrive at that same result a different way, but the main thing I'm wondering is, how do you also display that in terms of days? in terms of months? ex. 3 years, 3 months, 15 days between two dates is also, for example, 964 days, or 39 months, or something like that -- essentially the way this website acts:https://www.timeanddate.com/date/duration.html

that's the part I really can't figure out!!

2      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

From Paul's Working with dates

The point is that dates are hard, but Apple has provided us with stacks of helpers to make them less hard.

You need to work out what you what to display. This is very good from the WWDC 2020 Formatters: Make data human-friendly. Hope that helps.

Also if you subscribe to Hacking with Swift Plus. This is good Using dates safely and effectively

2      

how do you also display that in terms of days? in terms of months? ex. 3 years, 3 months, 15 days between two dates is also, for example, 964 days, or 39 months, or something like that

You do this by varying what you pass in as the first parameter to dateComponents(_:from:to:)

So, for instance, to get the difference between the same two dates but in days, you would do this:

let diffs = Calendar.current.dateComponents([.day], from: date1, to: date2)
print(diffs)
//returns: day: 1096 isLeapMonth: false

Or this code to get thew diff in hours and minutes:

let diffs = Calendar.current.dateComponents([.hour, .minute], from: date1, to: date2)
print(diffs)
//returns: hour: 26304 minute: 0 isLeapMonth: false

I forgot to mention this earlier, but you can access the properties of the diff result individually as well:

let diffs = Calendar.current.dateComponents([.hour, .minute], from: date1, to: date2)
print(diffs.hour!)
//returns: 26304

Note that they are optionals so you have to deal with that.

2      

Hi guys. Great topic!

Follow-up question: How do you list the days as dates in a range of dates?

like this: let now = Date()

let futureDay = now.addingTimeInterval(72 * 3600)

let dates = DateInterval(start: now, end: futureDay)

I'd like to see if there was some built-in trick to outputting an array like arrayOfDays: [Date] = [28-10-2020, 29-10-2020, 30-10-2020] from that DateInterval

The use case is such:

I'm asking the user to set a date range from A to B. Then I want to take alle the dates in that range, between A and B and present the user with a list of his/her chosen dates, and then add some data to those days, like a diary.

I've tried this a zillion ways, without luck.

2      

You can do something like this:

import Foundation

let now = Date()
let futureDate = Calendar.current.date(byAdding: .day, value: 30, to: now) ?? now
var dates: [Date] = []

Calendar.current.enumerateDates(startingAfter: now,
                                matching: DateComponents(hour: 0, minute: 0, second: 0),
                                matchingPolicy: .nextTime) { (date, match, stop) in
    if let date = date {
        if date > futureDate {
            stop = true
        } else {
            dates.append(date)
        }
    }
}
print(dates)

2      

And playing around a bit more in a playground:

extension Calendar {

    func dates(between startDate: Date, and endDate: Date, includingStart: Bool = false, includingEnd: Bool = true) -> [Date] {
        var dates: [Date] = []

        let cal = Calendar.current

        guard let startingAfter = cal.date(byAdding: .day, value: includingStart ? -1 : 0, to: startDate),
              let endingAt = cal.date(byAdding: .day, value: includingEnd ? 0 : -1, to: endDate) else {
            return dates
        }

        cal.enumerateDates(startingAfter: startingAfter,
                           matching: DateComponents(hour: 0, minute: 0, second: 0),
                           matchingPolicy: .nextTime) { (date, match, stop) in
            if let date = date {
                if date > endingAt {
                    stop = true
                } else {
                    dates.append(date)
                }
            }
        }

        return dates
    }

}

let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"

let now = formatter.date(from: "10/29/2020")!
let then = formatter.date(from: "11/30/2020")!

print(
    Calendar.current.dates(between: now,
                           and: then,
                           includingStart: true,
                           includingEnd: true)
        .map { formatter.string(from: $0) }
)

//result:
//["10/29/2020", "10/30/2020", "10/31/2020", "11/01/2020", "11/02/2020", "11/03/2020", 
//"11/04/2020", "11/05/2020", "11/06/2020", "11/07/2020", "11/08/2020", "11/09/2020", 
//"11/10/2020", "11/11/2020", "11/12/2020", "11/13/2020", "11/14/2020", "11/15/2020", 
//"11/16/2020", "11/17/2020", "11/18/2020", "11/19/2020", "11/20/2020", "11/21/2020", 
//"11/22/2020", "11/23/2020", "11/24/2020", "11/25/2020", "11/26/2020", "11/27/2020", 
//"11/28/2020", "11/29/2020", "11/30/2020"]

3      

.enumerateDates !!! Thats what I was looking for :D @roosterboy, you're a star mate!

Ok.. give an inch, take a mile. I have a follwo-up question that's been wrecking my brain for a few hours. Searching has yielded nothing, so I'll give the best forum for Swift a go. ;)

EDIT: I decided to create a short video to try to describe a question that I have, and hopefully it could help others struggling with the same question. I put it on YouTube :)

https://youtu.be/zz_juzfKwp4

I'm using a DatePicker in a view that I'm showing in a sheet. I want to let my users pick a from and to date. I'm trying to store this in an @Published variable contained within a class that conforms to @Observableobject, and the variable that I'm using to store it in is called as an @Observedobject..

But when I call up my sheet with the datepicker (and I'm using the binding) the picked value isn't stored in the variable 🤷🏻‍♂️

Any ideas?

2      

This works for me:

import SwiftUI

@main
struct DateTestApp: App {
    var body: some Scene {
        WindowGroup {
            DatePickerView(dateChoice: DateChoice())
        }
    }
}

class DateChoice: ObservableObject {
    @Published var startDate: Date = Date()
    @Published var endDate: Date = Date()
}

struct DatePickerView: View {

    @ObservedObject var dateChoice: DateChoice

    var body: some View {
        VStack {
            DatePicker(selection: $dateChoice.startDate, in: ...Date(), displayedComponents: .date) {
                Text("Select a start date")
            }

            DatePicker(selection: $dateChoice.endDate, in: ...Date(), displayedComponents: .date) {
                Text("Select an end date")
            }
        }
        .onChange(of: dateChoice.startDate) { _ in
            print(dateChoice.startDate)
        }
        .onChange(of: dateChoice.endDate) { _ in
            print(dateChoice.endDate)
        }
    }
}

The properties in the DateChoice class get updated as expected.

Is this similar to what you're doing?

2      

Thanks so much for the thorough replies @roosterboy

I figured what it was, in the. end. It was a silly mistake that I don't think will be much help to anyone 😅 However, I hope that someone looking for the solution to the .enumerateDates will find what they're looking for.

This is a good forum 💪

2      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.