Сравнение структур DateTime для поиска свободных слотов

Я хотел бы выполнить поиск по событиям всех пользователей в списке и получить все времена, когда каждый пользователь свободен 30 минут или больше между 7:00 и 19:00.

Однако есть одна загвоздка: если метод помечен как «повторяющийся», т. е. бит «повторяющийся» установлен на 1, то это событие повторяется в течение 52 недель после его начала (поэтому время недоступно). Извлечение этих событий осуществляется в хранимой процедуре.

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

List<string> usernames = //List of usernames.
DateTime start = //DateTime for start of period you would like to schedule meeting
DateTime end = //DateTime for end of period
//int mins = //duration of meeting (must be 30mins or greater)

foreach (string username in usernames) {
   //retrieve events for this user
    var db = Database.Open("mPlan");
    List<DateTime> startTimes;
    List<DateTime  endTimes;
    // This stored procedure returns all events of a user in a given time period, 
    // including recurring events.
    var record = db.Query("EXEC dbo.GetEvents @0, @1, @2", username, start, end);
    foreach(var record in result) {
          startTimes.Add(record.event_start);
          endTimes.Add(record.event_end);
    }
    // so now I have a list of all start times and end times of events
    // for one user and could save all this data in a list
  }

Структура таблицы:

DECLARE @Users TABLE
(    
    UserID   INT IDENTITY(1,1),
    Username VARCHAR(32)
);

DECLARE @Groups TABLE
(
    GroupID   INT IDENTITY(1,1),
    GroupName VARCHAR(32)
);

DECLARE @Membership TABLE
(
    UserID  INT,
    GroupID INT
);

DECLARE @event TABLE
(
    event_id    INT IDENTITY(1,1),
    event_start DATETIME,
    event_end   DATETIME,
    group_id    INT,
    recurring   BIT
);

Пример функциональности, которую я хотел бы:

Пользователь добавляет несколько пользователей из базы данных в список. Пользователь выбирает период времени, в течение которого он хотел бы встретиться со всеми этими пользователями. Мой алгоритм вычисляет все периоды времени, которые свободны для всех пользователей (т. е. время, которое подходит для встречи между всеми пользователями и составляет > 30 минут).

Дополнительная информация:

Примеры случаев:

  • Пользователь A пытается организовать встречу с пользователем B. Все временные интервалы бесплатно. Я хотел бы, чтобы алгоритм возвращал начало DateTime и DateTime конец всех возможных комбинаций времени начала и окончания время > 30 минут и == продолжительность (параметр).

  • Типичный случай: Пользователь А запланировал мероприятия на все время, кроме 18:00. 7 вечера. Он пытается организовать встречу с пользователем B в течение 1 час. У пользователя B нет организованных мероприятий - DateTime 18:00 и DateTime 7pm возвращаются, чтобы указать время начала и окончания встречи.

  • Повторяющийся случай: у пользователя А есть повторяющееся событие с 17:00 до 18:00 в понедельник. Он пытается организовать двухчасовую встречу в понедельник через шесть недель. Все комбинации DateTime start и DateTime end, где есть разница в 2 часа, возвращаются. Время с 17:00 до 19:00 не возвращается, так как это событие повторяющееся и происходит каждую неделю в течение 52 недель.

Вот хранимая процедура, которая извлекает все пользовательские события за заданный период времени (начало, конец):

ALTER PROCEDURE dbo.GetEvents 
  @UserName VARCHAR(50), 
  @StartDate DATETIME, 
  @EndDate DATETIME 
AS 

BEGIN 
-- DEFINE A CTE TO GET ALL GROUPS ASSOCIATED WITH THE CURRENT USER 
;WITH Groups AS  
(   SELECT  GroupID  
    FROM    Membership  m 
            INNER JOIN Users u 
                ON m.UserID = u.UserID 
    WHERE   Username = @UserName 
    GROUP BY GroupID 
), 
-- DEFINE A CTE TO GET ALL EVENTS FOR THE GROUPS DEFINED ABOVE 
AllEvents AS 
(   SELECT  e.* 
    FROM    event e 
            INNER JOIN Groups m  
                ON m.GroupID = e.group_id 
    UNION ALL 
    SELECT  e.event_id, e.title, e.description, 
      DATEADD(WEEK, w.weeks, e.event_start), 
      DATEADD(WEEK, w.weeks, e.event_end), 
      e.group_id, e.recurring 
    FROM    event e 
            INNER JOIN Groups m  
                ON m.GroupID = e.group_id 
            CROSS JOIN  
            (   SELECT  ROW_NUMBER() OVER (ORDER BY Object_ID) AS weeks 
                FROM    SYS.OBJECTS 
            ) AS w 
    WHERE  e.recurring = 1 
)    
-- GET ALL EVENTS WHERE THE EVENTS FALL IN THE PERIOD DEFINED 
SELECT  * 
FROM    AllEvents 
WHERE   Event_Start >= @StartDate 
AND     Event_End <= @EndDate 

END 
16
задан Aaron Bertrand 19 August 2019 в 14:56
поделиться