Alex
Alex

Reputation: 1058

Swift 4 How to get all events from calendar?

I am using Swift 4.1. And I want to write a function which will collect all events from all calendars in Calendar app of iOS. Thanks to this answer on stackoverflow: How to get all Events out of a Calendar (Swift) I was able to write my own class and call it Cale. Please, look at this:

import UIKit
import EventKit

class Cale {

    private func createDate(year: Int) -> Date {
        var components = DateComponents()
        components.year = year
        components.timeZone = TimeZone(secondsFromGMT: 0)

        return Calendar.current.date(from: components)!
    }

    private let eventStore = EKEventStore()

    private func get() {
        let calendars = eventStore.calendars(for: .event)

        for calendar in calendars {
            // This checking will remove Birthdays and Hollidays callendars
            guard calendar.allowsContentModifications else {
                continue
            }

            let start = createDate(year: 2016)
            let end = createDate(year: 2025)

            print("start: \(start)")
            print("  end: \(end)")

            let predicate = eventStore.predicateForEvents(withStart: start, end: end, calendars: [calendar])

            print("predicate: \(predicate)")

            let events = eventStore.events(matching: predicate)

            for event in events {
                print("    title: \(event.title!)")
                print("startDate: \(event.startDate!)")
                print("  endDate: \(event.endDate!)")
            }
        }
    }

    func checkStatusAndGetAllEvents() {
        let currentStatus = EKEventStore.authorizationStatus(for: EKEntityType.event)

        switch currentStatus {
        case .authorized:
            //print("authorized")
            self.get()
        case .notDetermined:
            //print("notDetermined")
            eventStore.requestAccess(to: .event) { accessGranted, error in
                if accessGranted {
                    self.get()
                } else {
                    print("Change Settings to Allow Access")
                }
            }
        case .restricted:
            print("restricted")
        case .denied:
            print("denied")
        }
    }
}

Quite simple class, you can use it, it is working but with one exception. The main function there is get() In this function I am creating predicate based on two dates: start and end. As you can see start date is:

2016-01-01 00:00:00 +0000

and end date is:

2025-01-01 00:00:00 +0000

But if we run the program we will see that predicate will be like this:

CADEventPredicate start:01/01/2016, 03:00; end:01/01/2020, 03:00; cals:( 2 )

Only from 2016 to 2020, 4 years! I have tested it on different dates, but I could get predicate with 4 years interval maximum. It means, it will not give me all events! So question is: How to get all events from calendar? If it possible, without using dates!

Thank you for any future help or advice!

Upvotes: 3

Views: 5074

Answers (2)

Cameron Stone
Cameron Stone

Reputation: 927

In case anyone is still wondering, Apple limited this to four years intentionally.

From predicateForEvents(withStart:end:calendars:):

For performance reasons, this method matches only those events within a four year time span. If the date range between startDate and endDate is greater than four years, it is shortened to the first four years.

If you want a range longer than that, I guess you'll have to wrap this in your own function to split it into four year chunks.

Upvotes: 4

Arshad Shaik
Arshad Shaik

Reputation: 1274

After spending so much time, i got a solution to my problem. My problem was as below,

event start date 2019-03-15 09:00:00 +0000
event end date 2019-03-15 14:00:00 +0000

the predicate as below,

CADEventPredicate start:15/03/19, 1:30 PM; end:15/03/19, 7:30 PM; cals:(null)

As i am from India, the predicate is adding GMT+5:30 to my actual event start and end time. I got a method from stack overflow, to convert to local & global timezone as below.

    extension Date {
    // Convert local time to UTC (or GMT)
    func toGlobalTime() -> Date {
        let timezone = TimeZone.current
        let seconds = -TimeInterval(timezone.secondsFromGMT(for: self))
        return Date(timeInterval: seconds, since: self)
    }

    // Convert UTC (or GMT) to local time
    func toLocalTime() -> Date {
        let timezone = TimeZone.current
        let seconds = TimeInterval(timezone.secondsFromGMT(for: self))
        return Date(timeInterval: seconds, since: self)
    }
}

While passing start and end date with time to predicate i am converting to globalTimeZone as below.

let predicate = eventStore.predicateForEvents(withStart: eventStartDateTime.toGlobalTime(), end: eventEndDateTime.toGlobalTime(), calendars: nil)

If you don't have time, you have only start & end dates, then use predicate as below,

event start date 2019-03-15 00:00:00 +0000
event end date 2019-03-15 00:00:00 +0000

let predicate = eventStore.predicateForEvents(withStart: eventStartDateTime, end: eventEndDateTime, calendars: nil)

Because if you don't have time and converting to globalTimeZone, you may face issues in deleting the events.

I hope it will help some one.

Upvotes: 0

Related Questions