Olá, amigos. Como vocês estão?

Contexto

Há um tempo átras participei de um projeto que lidava muito com agendamento de eventos, então, constantemente, tínhamos que validar se o horário agendado estava totalmente livre e eu falo totalmente livre, pois não poderia haver interseção entre os eventos, se isso ocorresse, seria um problemão para gente.

Então, na luta de de encontrar um algoritmo que validasse facilmente os horários dos eventos, eu desenvolvi alguns algoritmos desnecessáriamente complexos somente porque eu testava o mesmo cenário mais de uma vez. Na época eu não visualizava isso e após algum tempo, quando fui olhar o que tinha desenvolvido, vi que tinha deixado passar algumas coisas.

Aqui vou mostrá-lo a versão final do algoritmo, acredito que ele esteja bem otimizado e podemos usá-lo em produção.

Antes de começar, precisamos mapear nosso objeto principal, que é o evento:

Evento: é um objeto que possui uma data para acontecer, além de possuir um horário para começar e um horário para terminar. O período de duração do evento é um período contínuo, ou seja, significa que se começar as 8h e terminar as 12h, durante esse período, o evento acontece sem interrupções.

Restrição: Nenhum evento pode acontecer enquanto um outro evento estiver ocorrendo. No máximo o que pode acontecer é o final de um evento ser igual ao começo do outro, por exemplo, se um evento vai das 8h às 12h, o outro evento pode começar as 12h.

Cenários

Mapeado nosso problema, vamos para os cenários que podem acontecer (iremos esquecer os cenários em que os eventos são em dias distintos, já que nesse cenário é óbvio que os eventos não são conflitantes.):

Cenários

Em uma primeira analise do problema, podemos perceber que podemos ter 3 cenários que precisaremos tratar. Dado dois eventos (evento 1 e evento 2), um com o início e o fim definido (evento 1), temos o seguinte:

  1. O evento 2 pode começar antes do evento 1. Nesse cenário, caso o evento 2 termine antes do início do evento 1, ele será valido e poderá ser salvo, caso o contrário, ele não poderá ser salvo.
  2. O evento 2 pode começar entre o início e o fim do evento 1. Nesse caso o evento 2 sempre será inválido.
  3. O evento 2 pode começar após o final do evento 1. Nesse caso o evento 2 sempre será válido.

Do cenário mapeado acima, temos o seguinte:

const validation = (event1, event2) => {
    if (event2.start > event1.start) {
        if (event2.finish > event1.start) {
            // NãO É VÁLIDO
        } else {
            // VÁLIDO
        }
    } else if (event2.start > event1.finish) {
        // NãO É VÁLIDO
    } else {
        // VÁLIDO
    }
}

E com essa simplicidade conseguimos facilmente validar nossos eventos.

O código acima já atende o que desejamos, mas podemos deixar nossa solução um pouco mais elegante.

Atenção: se analisarmos bem os 3 cenários citados acima, conseguimos diminuir o número de cenários apenas para 1. Aqui vai a sacada. Fizemos a analise deixando o evento 1 fixo e variando o evento 2, agora iremos variar os dois e a partir do momento em que o início do evento 2 passar o início do evento 1, iremos mudar a forma de verificação (seria como transfomar o evento 1 em evento 2 e vice-versar), eu sei, deve está confuso, mas veja o código abaixo, acredito que irá entender o que eu quero dizer:

const secondValidation = (first, second) => {
    if (first.finish > second.start) {
        return 'CONFLITO'
    }
    return 'SEM CONFLITO'
}

const firstValidation = (event1, event2) => {
    return event1.start1 > event2.start ? secondValidation(event1, event2) : secondValidation(event2, event1)
}

firstValidation(event1, event2)

Pronto, agora temos uma solução elegante e simples para validar nossos eventos.

#Fim