Алгоритм, чтобы определить, находится ли данная дата / время между двумя парами дата / время - PullRequest
1 голос
/ 12 марта 2009

У меня есть массив дат в диапазоне одной недели, сохраненный необычным способом.

Даты хранятся в этом числовом формате: 12150

Слева направо:

1-я цифра обозначает день: 1 = воскресенье, 2 = понедельник, 3 = вторник, ...., 7 = суббота

следующие две цифры представляют час в 24-часовой системе: 00 = полночь, 23 = 23:00

.

следующие две цифры представляют минуты: 00-59

Учитывая дату ввода, а также дату начала и окончания, мне нужно знать, находится ли дата ввода между датой начала и окончания.

У меня сейчас есть алгоритм, который, как мне кажется, работает , работает 100% времени, но я не уверен.

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

Если нет, было бы здорово, если бы кто-то мог дважды проверить мою работу и убедиться, что она действительно работает для 100% действительных случаев.

Сейчас у меня есть:

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

}

Ответы [ 5 ]

1 голос
/ 12 марта 2009

Существует некоторая логическая ошибка с датами в этом формате. Поскольку информация о месяце и году отсутствует, вы не можете знать, какой календарный день отсутствует. например 50755 может быть четверг 12 марта 2009 года, но это может быть ровно неделю назад или 18 недель вперед. Это никогда не может быть на 100% уверенным, если любая дата в этом формате находится между любой другими 2 датами.

1 голос
/ 12 марта 2009

Здесь условие внутреннего if никогда не может быть истинным, поскольку endDate < startDate:

if (endDate < startDate) {
  if((inputDate + 72359) > startDate &&
    (inputDate + 72359) < endDate) {
    // never reached
    inRange = yes; 
  }

Следующее, если также не может быть оптимальным, поскольку первая часть всегда верна, а вторая часть просто идентична inputDate < endDate:

  if((inputDate + 72359) > startDate &&
     (inputDate + 72359) < (endDate + 72359))

Я думаю, вы хотите что-то вроде этого:

if (startDate < endDate)
  inRange = (startDate < inputDate) && (inputDate < endDate);
else
  inRange = (startDate < inputDate) || (inputDate < endDate);
1 голос
/ 12 марта 2009

Как насчет

const int MAX = 72460; // Or anything more than the highest legal value
inRange = (MAX + inputDate - startDate) % MAX < 
          (MAX + endDate - startDate) % MAX;

Это предполагает, конечно, что все даты правильно сформированы (согласно вашим спецификациям).

Это относится к случаю, когда начало «после» конца. (например, пятница находится в диапазоне, если начало - среда, а конец - понедельник)

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

Вот основной трюк:

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

Если вы действительно хотите сходить с ума (и еще труднее расшифровать)

const int MAX = 0x20000; 
const int MASK = 0x1FFFF;
int maxMinusStart = MAX - startDate;
inRange = (maxMinusStart + inputDate) & MASK < 
          (maxMinusStart + endDate) & MASK;

, что должно быть немного быстрее (торговый модуль для побитового и), что мы можем сделать, так как значение MAX на самом деле не имеет значения (пока оно превышает максимальное правильно сформированное значение), и мы можем выберите тот, который облегчает наши вычисления.

(И, конечно, вы можете заменить < на <=, если это то, что вам действительно нужно)

0 голосов
/ 12 марта 2009

Лучшим подходом может быть нормализация ваших данных с преобразованием значений дня недели в относительную дату начала. Примерно так:

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;

Я почти уверен, что это будет работать как написано. В любом случае, концепция чище, чем несколько сравнений.

0 голосов
/ 12 марта 2009

вы должны использовать> = и <=, если вы действительно хотите это в диапазоне </p>

скажи, что я выбрал эту дату 10000 или 72359, как бы ты справился с этим? это в диапазоне или нет?

также я не знал значения для startDate и endDate, так как вы не инициализировали его, исправьте меня, если я ошибся, переменная, которая не инициализировалась, будет начинаться с 0 или нуля или ''

поэтому я предполагаю, что startDate = 10000 и endDate 72359

кстати, почему вы выбираете этот тип массива (как int или строковое значение?), Почему первое значение было day? пример не даты:
010000 -> дата 1 числа месяца 00: 00
312359 -> дата 31 числа месяца 23: 59

но это зависит от вас: D

извините, если я ошибся, я посещал занятия по алгоритму только в университете, и это было 5 лет назад: D

...