Algoritmo para determinar se uma determinada data / hora entre dois pares de data / hora
-
10-07-2019 - |
Pergunta
Eu tenho uma matriz de datas em um intervalo uma semana armazenados de uma maneira incomum.
As datas são armazenadas neste formato numérico: 12150
Da esquerda para a direita:
1 dígito representa dias: 1 = domingo, 2 = Segunda-feira, 3 = Terça-feira, ...., 7 = sábado
próximos dois dígitos representam hora em um sistema de 24 horas: 00 = meia-noite, 23 = 11:00
próximos dois dígitos representam minutos: 00-59
Dada uma data de entrada e uma data de início e fim Eu preciso saber se a data de entrada está entre a data de início e fim.
Eu tenho um algoritmo agora que eu pensar funciona 100% do tempo, mas eu não tenho certeza.
Em qualquer caso, eu acho que é provavelmente a melhor e mais simples maneira de fazer isso e eu queria saber se alguém sabia o que o algoritmo foi.
Se não seria legal se alguém pudesse checar meu trabalho e verificar se ele realmente funciona para 100% dos casos válidos.
O que eu tenho agora é:
if (startDate < inputDate &&
endDate > inputDate) {
inRange = yes;
}
else if (endDate < startDate) {
if((inputDate + 72359) > startDate &&
(inputDate + 72359) < endDate) {
inRange = yes;
}
else if((inputDate + 72359) > startDate &&
(inputDate + 72359) < (endDate + 72359)) {
inRange = yes;
}
}
Solução
Como cerca
const int MAX = 72460; // Or anything more than the highest legal value
inRange = (MAX + inputDate - startDate) % MAX <
(MAX + endDate - startDate) % MAX;
Isso pressupõe, naturalmente, que todas as datas estão bem formados (de acordo com suas especificações).
Este aborda o caso em que o início é "após" o fim. (Por exemplo, sexta-feira é na faixa se o início for quarta-feira e final é segunda-feira)
Pode demorar um segundo para ver (o que provavelmente não é bom, porque a leitura é geralmente o mais importante), mas acho que ela não funciona.
Aqui está o truque básico:
Legend: 0: Minimum time M: Maximum time S: Start time 1,2,3: Input Time test points E: End Time The S E => Not in range 2 In range 3 > E => Not in range The S > E case 0 M Original -1--E----2---S--3-- Add Max -------------------1--E----2---S--3-- Subtract StartDate ------1--E----2---S--3-- % Max S--3--1--E----2---- 1 In range 2 > E => Not in range 3 In range
Se você realmente quer ir porcas (e ser ainda mais difícil de decifrar)
const int MAX = 0x20000;
const int MASK = 0x1FFFF;
int maxMinusStart = MAX - startDate;
inRange = (maxMinusStart + inputDate) & MASK <
(maxMinusStart + endDate) & MASK;
que deveria ser um pouco mais rápido (módulo de negociação por um bit a bit e) que nós podemos fazer, já que o valor de MAX realmente não importa (contanto que excede o valor máximo bem-formado) e nós estamos livres para escolher um que faz com que nossos cálculos fácil.
(E, claro, você pode substituir o <
com um <=
se é isso que você realmente precisa)
Outras dicas
Há algum erro de lógica com datas em que formato. Desde que a informação mês e ano está faltando, você não pode saber o dia de calendário está faltando. por exemplo. 50755 poderia ser Quinta-feira 12 Março de 2009, mas poderia muito bem ser exatamente há uma semana, ou 18 semanas. Que, para que você nunca poderia ser 100% de certeza se qualquer data em que formato é entre qualquer outros 2 datas.
Aqui a condição do if
interior nunca pode ser verdade, já que endDate < startDate
:
if (endDate < startDate) {
if((inputDate + 72359) > startDate &&
(inputDate + 72359) < endDate) {
// never reached
inRange = yes;
}
A seguir, se pode também não ser o ideal, uma vez que a primeira parte é sempre verdadeira e a segunda parte é apenas idêntico ao inputDate < endDate
:
if((inputDate + 72359) > startDate &&
(inputDate + 72359) < (endDate + 72359))
Eu acho que você quer algo parecido com isto:
if (startDate < endDate)
inRange = (startDate < inputDate) && (inputDate < endDate);
else
inRange = (startDate < inputDate) || (inputDate < endDate);
você deve usar> = e <= se você realmente quer na gama
dizer que eu escolher esta data 10000 ou 72359, como você lidar com isso? é na faixa ou não?
Também eu não sabia valor para startDate e endDate desde que você não inicializou-lo, me corrija se eu estava errado, variável que não inicializado vai começar com 0 ou nulo ou ''
assim que eu assumir o startDate = 10000 e endDate 72359
btw por que você escolher este tipo de array (como int ou string valor?) Porque primeiro valor era dia? Não exemplo, data:
010000 -> data de 1º do mês 00:00
312.359 -> data 31th do mês 23:59
mas cabe a você: D
desculpe se eu estava errado i levou algoritmo de classe apenas em universidade e foi 5 anos atrás: D
Uma abordagem melhor seria para normalizar seus dados de conversão de todo o dia dos valores semana para ser relativo à data de início. Algo parecido com isto:
const int dayScale = 10000; // scale factor for the day of the week
int NormalizeDate(int date, int startDay)
{
int day = (date / dayScale) - 1; // this would be a lot easier if Sunday was 0
int sday = startDay - 1;
if (day < sday)
day = (day + 7 - sday) % 7;
return ((day+1) * dayScale) + (date % dayScale);
}
int startDay = startDate / dayScale; // isolate the day of the week
int normalizedStartDate = NormalizeDate(startDate, startDay);
int normalizedEndDate = NormalizeDate(endDate, startDay);
int normalizedInputDate = NormalizeDate(inputDate, startDay);
inRange = normalizedInputDate >= normalizedStartDate &&
normalizedInputDate <= normalizedEndDate;
Tenho a certeza que isso vai funcionar como escrito. Em qualquer caso, o conceito é mais limpa que as comparações múltiplas.