Как лучше всего моделировать повторяющиеся события в приложении календаря? - PullRequest
210 голосов
/ 17 сентября 2008

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

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

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

Ответы [ 18 ]

84 голосов
/ 17 сентября 2008

Я бы использовал концепцию «ссылка» для всех будущих повторяющихся событий. Они динамически отображаются в календаре и ссылаются на один ссылочный объект. Когда события произошли, связь разрывается, и событие становится автономным экземпляром. Если вы попытаетесь отредактировать повторяющееся событие, то предложите изменить все будущие элементы (т.е. изменить одну связанную ссылку) или изменить только этот экземпляр (в этом случае преобразовать его в автономный экземпляр и затем внести изменения). Последний случай немного проблематичен, так как вам нужно отслеживать в своем повторяющемся списке все будущие события, которые были преобразованы в один экземпляр. Но это вполне выполнимо.

Итак, по сути, есть 2 класса событий - единичные экземпляры и повторяющиеся события.

53 голосов
/ 05 декабря 2010

Мартин Фаулер - Повторяющиеся события для календарей содержит некоторые интересные идеи и шаблоны.

Runt gem реализует этот шаблон.

32 голосов
/ 19 мая 2009

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

Решение 1 - без экземпляров

Сохранять исходные данные о встрече + повторения, не сохранять все экземпляры.

Проблемы:

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

Решение 2 - хранить экземпляры

Хранить все от 1, но также и все экземпляры, связанные с исходной встречей.

Проблемы:

  • Занимает много места (но место дешевое, настолько незначительное)
  • Исключения должны обрабатываться изящно, особенно если вы вернетесь и отредактируете исходную встречу после создания исключения. Например, если вы переместили третий экземпляр на один день вперед, что если вы вернетесь назад и отредактируете время первоначальной встречи, повторно вставите другую в исходный день и оставите перенесенную? Отсоединить перемещенный? Попробовать поменять перемещённое соответственно?

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

16 голосов
/ 23 октября 2010

Я работаю со следующим:

и находящийся в процессе разработки камень, расширяющий форму с типом ввода: recurring (form.schedule :as => :recurring), который визуализирует интерфейс, подобный iCal, и before_filter для повторной сериализации представления в объект IceCube, гетто-ly .

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


Так что это мне дает? Индексируемые, редактируемые, повторяющиеся атрибуты.

events хранит экземпляр одного дня и используется в представлении календаря / помощник скажем, task.schedule хранит объект yaml'd IceCube, поэтому вы можете делать вызовы вроде: task.schedule.next_suggestion.

Резюме: я использую две модели, одну плоскую, для отображения календаря, и один атрибут для функциональности.

16 голосов
/ 17 сентября 2008

Возможно, вы захотите взглянуть на реализации программного обеспечения iCalendar или сам стандарт ( RFC 2445 RFC 5545 ). Быстро приходят на ум проекты Mozilla http://www.mozilla.org/projects/calendar/ Быстрый поиск также показывает http://icalendar.rubyforge.org/.

Другие варианты могут быть рассмотрены в зависимости от того, как вы собираетесь хранить события. Вы строите свою собственную схему базы данных? Используя что-то на основе iCalendar и т. Д .?

13 голосов
/ 13 июля 2016

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

Некоторые ключевые моменты:

  • Сохранение повторяемости в формате iCal RRULE - это одно колесо, которое вы действительно не хотите изобретать
  • НЕ храните отдельные повторяющиеся события экземпляры как строки в вашей базе данных! Всегда сохраняйте шаблон повторения.
  • Существует множество способов разработки схемы событий / исключений, но приведен пример базовой отправной точки
  • Все значения даты / времени должны быть сохранены в UTC и преобразованы в локальные для отображения
  • Дата окончания, сохраняемая для повторяющегося события, всегда должна быть конечной датой диапазона повторения (или «максимальная дата» вашей платформы, если повторяющаяся «навсегда»), а продолжительность события должна храниться отдельно. Это сделано для того, чтобы обеспечить разумный способ запроса событий позже.
  • Включено некоторое обсуждение создания экземпляров событий и стратегий редактирования повторений

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

6 голосов
/ 09 ноября 2009

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

http://github.com/bakineggs/recurring_events_for

Затем я использую runt для динамического вычисления дат.

https://github.com/mlipper/runt

5 голосов
/ 17 сентября 2008
  1. Отслеживать правило повторения (возможно, на основе iCalendar, за @ Крис К. ). Это будет включать в себя шаблон и диапазон (каждый третий вторник для 10 случаев).
  2. Если вы хотите отредактировать / удалить конкретное вхождение, отслеживайте даты исключений для указанного выше правила повторения (даты, когда событие не происходит, как указано в правиле).
  3. Если вы удалили, это все, что вам нужно, если вы отредактировали, создайте другое событие и присвойте ему родительский идентификатор, установленный для основного события. Вы можете выбрать, включать ли всю информацию о главном событии в эту запись, или она содержит только изменения и наследует все, что не меняется.

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

Надеюсь, это поможет!

4 голосов
/ 17 сентября 2008

Я бы порекомендовал использовать мощь библиотеки дат и семантику модуля диапазона ruby. Повторяющееся событие - это действительно время, диапазон дат (начало и конец) и обычно один день недели. Используя дату и диапазон, вы можете ответить на любой вопрос:

#!/usr/bin/ruby
require 'date'

start_date = Date.parse('2008-01-01')
end_date   = Date.parse('2008-04-01')
wday = 5 # friday

(start_date..end_date).select{|d| d.wday == wday}.map{|d| d.to_s}.inspect

Производит все дни события, включая високосный год!

# =>"[\"2008-01-04\", \"2008-01-11\", \"2008-01-18\", \"2008-01-25\", \"2008-02-01\", \"2008-02-08\", \"2008-02-15\", \"2008-02-22\", \"2008-02-29\", \"2008-03-07\", \"2008-03-14\", \"2008-03-21\", \"2008-03-28\"]"
3 голосов
/ 17 сентября 2008

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

...