Swift 4 Как получить все события из календаря?

Я использую Swift 4.1. И я хочу написать функцию, которая будет собирать все события из всех календарей в приложении Календарь iOS. Благодаря этому ответу на stackru: Как получить все события из календаря (Swift) я смог написать свой собственный class и назовите это Cale, Пожалуйста, посмотрите на это:

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

Довольно простой класс, вы можете использовать его, он работает, но с одним исключением. Основная функция там есть get() В этой функции я создаю предикат, основанный на двух датах: начало и конец. Как вы видите, дата начала:

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

и дата окончания:

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

Но если мы запустим программу, мы увидим, что предикат будет выглядеть так:

Начало CADEventPredicate: 01.01.2016, 03:00; конец: 01.01.2020, 03:00; cals:( 2)

Только с 2016 по 2020, 4 года! Я проверил это в разные даты, но я мог получить предикат с интервалом максимум 4 года. Значит, это не даст мне все события! Итак, вопрос: как получить все события из календаря? Если это возможно, без использования даты!

Спасибо за любую будущую помощь или совет!

0 ответов

В случае, если кому-то все еще интересно, Apple намеренно ограничила это четырьмя годами.

Из predicateForEvents(withStart:end:calendars:):

По соображениям производительности этот метод сопоставляет только те события в течение четырехлетнего промежутка времени. Если диапазон дат между startDate и endDate превышает четыре года, он сокращается до первых четырех лет.

Если вам нужен более длинный диапазон, я думаю, вам придется обернуть его в свою собственную функцию, чтобы разделить его на четыре года.

Потратив так много времени, я нашел решение своей проблемы. Моя проблема была как ниже,

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

предикат, как показано ниже,

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

Поскольку я из Индии, предикат добавляет GMT+5:30 к фактическому времени начала и окончания события. Я получил метод от переполнения стека, чтобы преобразовать в локальный и глобальный часовой пояс, как показано ниже.

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

Проходя дату начала и окончания со временем, чтобы предсказать, я конвертирую в globalTimeZone, как показано ниже.

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

Если у вас нет времени, у вас есть только даты начала и окончания, а затем используйте предикат, как показано ниже,

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)

Потому что, если у вас нет времени и конвертации в globalTimeZone, вы можете столкнуться с проблемами при удалении событий.

Надеюсь, это кому-нибудь поможет.

Другие вопросы по тегам