Должен ли я хранить даты или правила повторения в моей базе данных при создании приложения календаря? - PullRequest
27 голосов
/ 21 ноября 2010

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

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

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

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

Ответы [ 7 ]

46 голосов
/ 14 апреля 2012

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

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

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

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

8 голосов
/ 15 апреля 2012

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

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

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

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

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

Примечание: Возможно, вы захотите рассмотреть поддержку, выходящую за рамки того, что определено в rfc5545 с точки зрения правил повторяемости, а также добавить поддержку для религиозных повторяющихся правил ( см. введение USNO в календари или в печатном издании «Календарные вычисления» (третье издание) от Э. Рейнгол и Н. Дершовиц).

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

7 голосов
/ 21 ноября 2010

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

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

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

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

3 голосов
/ 21 ноября 2010

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

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

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

1 голос
/ 15 апреля 2012

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

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

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

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

0 голосов
/ 02 июля 2018

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

В те времена мои серверы были ограничены io из-за большого количества процессоров, которые ничего не делали. В настоящее время у вас есть ssd (если вы можете себе это позволить, в противном случае у вас осталось старое вращающееся hd), но обратите внимание, что количество ядер также увеличилось.

Хорошая особенность такого рода расчетов заключается в том, что вы можете легко разделить их и передать их множеству ядер или даже нескольким дешевым серверам в локальной сети. Часто дешевле, чем настройка кластера nosql или использование полного кластера баз данных.

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

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

0 голосов
/ 21 ноября 2010

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

1) Каждый день в 10 утра, кроме среды

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

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

и т.д ..

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

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

...