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;   
        }

}
Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top