Должен ли я хранить даты или правила повторения в моей базе данных при создании приложения календаря?

Я создаю приложение для календаря (ASP.NET MVC) (думаю, простую версию Outlook), и я хочу начать поддерживать события календаря, которые повторяются (ежемесячно, ежегодно и т.д.)

Сейчас я храню фактические даты в своем, но я хотел выяснить, имеет ли смысл продолжать хранить даты (с некоторым очевидным отключением), или я должен сохранить варианты повторения и генерировать даты на лету.

Это заставило меня задуматься, как Outlook, Google Mail и т.д. делает это или любую другую услугу, которая поддерживает повторяющиеся элементы календаря.

Есть ли какие-либо предложения по этому поводу?

Ответ 1

Разделите свои данные на две части: "канонические" данные (правило повторения) и "обслуживание" (сгенерированные даты, только для чтения, кроме регенерации). Если канонические данные изменяются, восстановите "обслуживающие" данные в этой точке. Для бесконечных повторений сохраняйте некоторое количество экземпляров и генерируйте больше, если вы закончите (например, если пользователь просматривает свой календарь на 2020 год).

Если у вас была бесконечная скорость процессора, вам нужны только канонические данные, но на самом деле выполнение всей обработки даты и времени для всех правил повторения на каждом просмотре страницы, вероятно, будет слишком трудоемким... поэтому вы скомпилируете некоторое хранилище (и сложность), чтобы сохранить это повторное вычисление. Хранение обычно довольно дешево, по сравнению с вычислениями, требуемыми для большого количества событий. Если вам нужно только сохранить даты событий, это действительно очень дешево - вы можете легко использовать целое число из 4 байтов для представления даты, а затем сгенерировать полную дату/время, исходя из того, что ваши рекурсии относятся ко всем датам. Для повторяющихся по времени повторений (например, "каждые три часа" ) вы можете использовать полные моменты времени в UTC - 8 байтов будут представлять это до довольно прекрасного разрешения до тех пор, пока вам, вероятно, понадобятся.

Вам нужно быть осторожным, чтобы сохранить достоверность, хотя, если текущая встреча меняется сегодня, это не изменится, когда это произошло в прошлом... поэтому вы, вероятно, захотите также иметь канонические данные только для чтения о том, когда повторяются фактически произошло. Очевидно, вы не захотите, чтобы прошлое было вечно, поэтому вы, вероятно, захотите "собирать мусор" более чем на несколько лет, в зависимости от ваших ограничений на хранение.

Вам также может потребоваться возможность добавления заметок и исключений (например, "встреча не происходит сегодня из-за государственного праздника" или "переместилась на 4 часа дня" ) в каждом случае. Это становится очень забавным, когда вы меняете повторение - если вы меняете "каждый понедельник" на "каждый вторник", вы сохраняете исключения или нет? Как вы сравниваете исключения, когда вы меняете "каждый день" на "каждую неделю"? Это не вопросы, связанные непосредственно с хранилищем, но решения по хранению повлияют на то, насколько легко реализовать любую политику, которую вы решаете.

Ответ 2

Мне пришлось создать систему, которая работала с расписанием, и мы сделали то и другое. Вот что мы имели

  • набор таблиц, отслеживающих расписание.
  • таблица, в которой отслеживаются предыдущие экземпляры расписания (когда они на самом деле произошли)
  • таблица, в которой отслеживается последний и следующий экземпляр (когда следующий элемент должен произойти в последний раз). Эта таблица не нужна, но мы ее использовали, потому что в противном случае вы постоянно вычисляли бы, если элемент должен появиться сейчас

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

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

Ответ 3

Вам нужно будет обрабатывать отдельно события и события.

МЕРОПРИЯТИЕ: Для событий вам нужно будет хранить правила возврата (которые могут быть rrule, как указано rfc5545, но также явный набор дат, таких как rdate в rfc5545), но также и исключения (см. Exdate of rfc5545 и, возможно, exrule, как в rfc2445). Вам также необходимо будет отслеживать изменения в этих правилах: Изменения в rdate, exdate не представляют проблемы, когда они происходят в будущем и игнорируются для прошлых дат. Изменения в rrule более сложны, так как они влияют на предыдущие случаи. Мое личное предпочтение заключается в добавлении определенного свойства для старого и нового rrule для указания их даты начала и окончания срока действия.

если событие имеет ограниченный промежуток времени (например, свойство COUNT или UNTIL присутствует), вы должны сохранить его начало и конец в своей таблице, чтобы упростить запрос событий (особенно при поиске случаев вне вашего предварительно рассчитанного временного окна (см. ниже), это может помочь уменьшить количество событий, для которых нужно переделать вычисление).

ПРОСМОТРЫ WISE: для случаев вы должны хранить экземпляры в пределах предопределенного окна вокруг настоящего (скажем +/- 6 месяцев или 12 месяцев и рассчитывать на регулярной основе) и вести учет этого, чтобы разрешить пересчет, если ваши пользователи захотят увидеть в будущем (для проблемы выступлений). вы также должны рассмотреть возможность вычисления индекса (RECURRENCE-ID), чтобы облегчить поиск следующего события.

меньше в фоновом режиме, но больше на интерфейсе вы также должны отслеживать изменения tzid, чтобы спросить пользователя, если событие, которое было запланировано на заданном tzid, если оно предназначено для пребывания в текущем часовом поясе нуждается в обновлении (подумайте о ком-то на острове Самоа, у которого было запланировано совещание в пятницу, 30 декабря 2011 года, до того, как страна решила, что этот день не будет существовать), аналогичным образом вы можете спросить, означает ли событие, которое происходит во время летнего времени "никогда не бывает" или "произойдет дважды" (подробнее об этой теме здесь)

Примечание: вы можете рассмотреть возможность поддержки за пределами того, что определено в rfc5545 с точки зрения правил повторения, а также добавить поддержку религиозных повторяющихся правил (см. введение USNO в календари или в печати "Календарные вычисления" (Третье издание) от E. Reingol и N. Dershowitz).

Поскольку вы спрашиваете о существующей реализации, вы можете легко проверить схему базы данных sunbird (sqlite) или Apple с открытым исходным кодом Календарь и сервер контактов доступен более полный список существующих проектов с открытым исходным кодом для серверов caldav (который, вероятно, является частью того, что вы ищете) здесь)

Ответ 4

Я бы определенно использовал ваш второй вариант. Используйте разные варианты повторения, храните их отдельно и вычисляйте "на лету". Хранение всех этих дат будет лодкой данных, которые не нужны.

Вот хороший ответ, чтобы ответить на ваш вопрос.
Структура данных для хранения повторяющихся событий?

Также, как побочная заметка. Я начал хранить все как время UTC, так что у вас есть общая базовая линия, если вам когда-либо понадобится использовать несколько часовых поясов.

Ответ 5

Вам нужно запомнить некоторые из них. Пользователь может отредактировать одно из событий, оставив других нетронутыми (вероятно, вы столкнулись с вопросом: "Вы хотите редактировать все повторяющиеся события или только этот?" В некоторых календарях, то есть Windows Mobile).

Также вы можете сохранить прошлые события и не удалять их, когда пользователь удаляет повторяющееся событие.

Если вы храните все остальные или сгенерируете их, это деталь реализации. Я бы предпочел сгенерировать их, если это возможно.

В любом случае вам нужно будет иметь идентификатор повторяющегося события, хранящегося в каждом событии, плюс некоторый флаг, сообщающий вам, если событие было изменено позже. Или в более сложном подходе - флаг для каждого свойства события, указывающий, если это значение по умолчанию (из повторяющегося события) или если оно было изменено для этого конкретного экземпляра. Это понадобится вам, когда пользователь решит отредактировать повторяющееся событие.

Ответ 6

У меня была аналогичная проблема в веб-приложении, которое я сделал несколько лет назад (теперь может быть лучше::)). Я хотел включить планировщик, который имел всю функциональность повторяющихся событий, обрабатывал время, дни, недели, месяцы, годы и исключения, чтобы у меня были такие правила, как:

1) Каждый день в 10 утра за исключением среды

2) Каждые 2 часа с максимум 4 итерациями в день

3) Каждый первый понедельник месяца

и т.д..

Сохранение повторяющихся дат/времени было возможным, но негибким. Каждая итерация вашего события изменяется, когда "максимум" будет. И как далеко вперед вы смотрите?

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