Home > Enterprise >  Search for event date falling between two Cloud Firestore timestamps in SwiftUI
Search for event date falling between two Cloud Firestore timestamps in SwiftUI

Time:07-13

Primarily what I’m looking to do, is to pull out documents from my Cloud Firestore when the current date falls between two timestamp fields. I have included simplified code snippets below. Hopefully it makes sense, as I’m a noob.

I have a Cloud Firestore collection named ‘calendar’ with numerous documents in it.

Each document has an event ‘title’ field plus two timestamp fields ‘datebegin’ and ‘dateend’.

struct Calendar: Decodable, Identifiable {
    var title: String = ""
    var datebegin: Date = Date()
    var dateend: Date = Date()
}

I am parsing out the values from each document into event calendar instances:

class Calendars: ObservableObject {

    let db = Firestore.firestore()

  @Published var calendars = [Calendar]()

  init() {
              getDatabaseModules()
         }

 func getDatabaseModules() {
        db.collection("calendar")
            .getDocuments { snapshot, error in
            if error == nil && snapshot != nil {
                
                var calendars = [Calendar]()
                
                for event in snapshot!.documents {
                    
                    var e = Calendar()

                    e.title = event["title"] as? String ?? ""
                    e.datebegin = (event["datebegin"] as? Timestamp)?.dateValue() ?? Date()
                    e.dateend = (event["dateend"] as? Timestamp)?.dateValue() ?? Date()
                    
                    calendars.append(e)
                }
                
                DispatchQueue.main.async {
                    self.calendars = calendars
                }
            }
        }
    }

And I have been able to pull out the data in my view, so I know that I am able to access it okay:

struct HomeView: View {
    
    @EnvironmentObject var calendars: Calendars

    var body: some View {

        ForEach(0..<calendars.calendars.count, id: \.self) { events in
            Text("\(calendars.calendars[events].title)")
            Text("\(calendars.calendars[events].datebegin)")
            Text("\(calendars.calendars[events].dateend)”)
        }
    }
}
  1. Primarily what I’m looking to do, is only pull out only the calendar events when the current date (i.e. now) falls between the datebegin and dateend.

  2. And then I would subsequently sort the resulting list by day ideally (based on the Day of datebegin), so it should end up with something like this (for an example with 9 documents that meet the criteria):

Monday

  • document2.title
  • document5.title

Tuesday

  • document4.title
  • document9.title

Wednesday

  • document3.title
  • document6.title
  • document7.title

Friday

  • document1.title

Saturday

  • Document8.title

Any advice is appreciated and can provide more info as needed.

CodePudding user response:

you could try this approach, using some functions to ...pull out only the calendar events when the current date (i.e. now) falls between the datebegin and dateend... and sorting the results based on time to ...then I would subsequently sort the resulting list by day ideally (based on the Day of datebegin).... Adjust the approach to suit your desired time accuracy, for example, day, weeks ...

Note, it is not a good idea to use the name Calendar for your struct, as Swift already has a Calendar declared.

struct ContentView: View {
    @StateObject var model = Calendars()
    
    var body: some View {
        HomeView().environmentObject(model)
    }
}

struct HomeView: View {
    @EnvironmentObject var calendars: Calendars
    let now = Date()
    
    var body: some View {
        // -- here 
        List {
            ForEach(calendars.allBetween(now).sorted(by: {$0.datebegin < $1.datebegin})) { event in
                VStack {
                    Text("\(event.title)")
                    Text("\(event.datebegin)")
                    Text("\(event.dateend)")
                }
            }
        }
    }
}

struct Calendar: Decodable, Identifiable {
    let id = UUID()  // <-- here
    var title: String = ""
    var datebegin: Date = Date()
    var dateend: Date = Date()
    
    // -- here
    func isBetween(_ date: Date) -> Bool {
        datebegin.timeIntervalSince1970 < date.timeIntervalSince1970
        &&
        date.timeIntervalSince1970 < dateend.timeIntervalSince1970
    }

    // alternatively, day comparison 
    func isBetweenDay(_ date: Date) -> Bool {
        !(Foundation.Calendar.current.compare(date, to: datebegin, toGranularity: .day) == .orderedAscending || Foundation.Calendar.current.compare(date, to: dateend, toGranularity: .day) == .orderedDescending)
    }
    
}

class Calendars: ObservableObject {
    let db = Firestore.firestore()
    @Published var calendars = [Calendar]()
    
    init() {
        getDatabaseModules()
    }
    
    // -- here
    func allBetween(_ date: Date) -> [Calendar] {
        calendars.filter{ $0.isBetweenDay(date) } // <-- or $0.isBetween(date)
    }

    func getDatabaseModules() {
                db.collection("calendar")
                    .getDocuments { snapshot, error in
                        if error == nil && snapshot != nil {
                            var calendars = [Calendar]()
                            for event in snapshot!.documents {
                                var e = Calendar()
                                e.title = event["title"] as? String ?? ""
                                e.datebegin = (event["datebegin"] as? Timestamp)?.dateValue() ?? Date()
                                e.dateend = (event["dateend"] as? Timestamp)?.dateValue() ?? Date()
                                calendars.append(e)
                            }
                            DispatchQueue.main.async {
                                self.calendars = calendars
                            }
                        }
                    }
    }
}
    
  • Related