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

SOLVED: Array of dates

Forums > SwiftUI

Hello, I have an array of dates and I'm trying to filter it to get, in three different array today dates - future dates - past dates.

// Appointment is a CoreData entity with a property date: Date
@Published var scheduledAppointments: [Appointment] = [] // this array should contain future appointments from 00:00 of tomorrow and later.
@Published var pastAppointments: [Appointment] = [] // this array should contain past appointments from 23:59 of yesterday and before.
@Published var todayAppointments: [Appointment] = [] // this array should contain today appointments from 00:00 to 23:59.

I've tried a lot of solutions (many of which didn't work) and I end up with this solution but i think is weird.

    func getTodayAppointments() {
        let allAppointments = pet.appointments?.allObjects as? [Appointment] ?? []
        let today = allAppointments.filter { appointment in
            let appointmentComponents = Calendar.current.dateComponents([.day, .year, .month], from: appointment.appointmentDate)
            let todayComponents = Calendar.current.dateComponents([.day, .year, .month], from: Date())
            return appointmentComponents == todayComponents
        }
        todayAppointments = today.sorted {
            $0.appointmentDate > $1.appointmentDate
        }
    }

    func getScheduledAppointments() {
        let allAppointments = pet.appointments?.allObjects as? [Appointment] ?? []
        let scheduled = allAppointments.filter { appointment in
            let todaySeconds = getTodaySeconds()
            return appointment.appointmentDate >= Date.now.addingTimeInterval(Double(86400 - todaySeconds - 1))
        }
        scheduledAppointments = scheduled.sorted {
            $0.appointmentDate > $1.appointmentDate
        }
    }

    func getPastAppointments() {
        let allAppointments = pet.appointments?.allObjects as? [Appointment] ?? []
        let past = allAppointments.filter { appointment in
            let todaySeconds = getTodaySeconds()
            return appointment.appointmentDate <= Date.now.addingTimeInterval(Double(-todaySeconds - 1))
        }

        pastAppointments = past.sorted {
            $0.appointmentDate > $1.appointmentDate
        }
    }

    // With this function I get the seconds passed today and then subtract or add this value to .addingTimeInterval otherwise some appointments were not displayed or displayed in more than 1 array.
    func getTodaySeconds() -> Int {
        let today = Calendar.current.dateComponents([.hour, .minute, .second], from: Date())
        let minuteInSeconds = (today.minute ?? 0) * 60
        let hourInSeconds = (today.hour ?? 0) * 3600
        let seconds = today.second ?? 0
        return minuteInSeconds + hourInSeconds + seconds
    }

Here the result on a list

Can you suggest improvements to this code? Thank you! ( English is not my main language, I hope you understand )

2      

Here is some code I whipped up in a playground. I think it should point you in the right direction...

//build up an array of dates to work with
let formatter = ISO8601DateFormatter()
let arrayOfDates: [Date] = [
    //these are in ISO8601 string format
    "2022-03-25T14:32:15+00:00",  //today
    "2022-03-24T14:32:15+00:00",  //past
    "2022-03-29T14:32:15+00:00",  //future
    "2022-03-21T14:32:15+00:00",  //past
    "2022-03-27T14:32:15+00:00",  //future
    "2022-03-23T14:32:15+00:00",  //past
].map {
    //so we map over them with a formatter
    //to turn them into dates
    formatter.date(from: $0)!
}

func getTodayAppointments(from dates: [Date]) -> [Date] {
    let cal = Calendar.current
    return dates.filter {
        cal.isDateInToday($0)
    }
}
print(getTodayAppointments(from: arrayOfDates))
//[2022-03-25 14:32:15 +0000]

func getScheduledAppointments(from dates: [Date]) -> [Date] {
    let cal = Calendar.current
    return dates.filter {
        cal.compare($0, to: .now, toGranularity: .day) == .orderedDescending
    }
}
print(getScheduledAppointments(from: arrayOfDates))
//[2022-03-29 14:32:15 +0000, 2022-03-27 14:32:15 +0000]

func getPastAppointments(from dates: [Date]) -> [Date] {
    let cal = Calendar.current
    return dates.filter {
        cal.compare($0, to: .now, toGranularity: .day) == .orderedAscending
    }
}
print(getPastAppointments(from: arrayOfDates))
//[2022-03-24 14:32:15 +0000, 2022-03-21 14:32:15 +0000, 2022-03-23 14:32:15 +0000]

compare(_:to:toGranularity:) returns ".orderedSame if the two dates are equal in the given component and all larger components; otherwise, either .orderedAscending or .orderedDescending."

3      

Thank you, your code works fine and it's cleaner than mine.

2      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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.