确定给定日期/时间是否在两个日期/时间对之间的算法

时间:2009-03-12 05:39:22

标签: algorithm datetime math date mathematical-optimization

我有一个以不寻常的方式存储的一周范围内的日期数组。

日期以此数字格式存储:12150

从左到右:

第1位代表日:1 =星期日,2 =星期一,3 =星期二,....,7 =星期六

接下来的两位数表示24小时制中的小时:00 =午夜,23 =晚上11点

接下来的两位数代表分钟: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;   
        }

}

6 个答案:

答案 0 :(得分:1)

怎么样

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的值并不重要(只要它超过最大格式良好的值),我们可以做的,它应该稍快一点(按位和交易模数),我们可以自由地选择一个使我们的计算变得容易的。

(当然,如果您真正需要的话,可以将<替换为<=

答案 1 :(得分:1)

该格式的日期存在一些逻辑错误。由于缺少月份和年份信息,您无法知道缺少哪个日历日。例如50755可能是2009年3月12日星期四,但它可能恰好是一周前,或者提前18周。如果该格式的任何日期在任何其他2个日期之间,那么对您来说永远不会100%确定。

答案 2 :(得分:1)

此处内部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);

答案 3 :(得分:0)

如果你真的希望它在范围

,你应该使用&gt; =和&lt; =

说我选择这个日期10000或72359,你将如何处理这个?是否在范围内?

我也不知道startDate和endDate的值,因为你没有初始化它,纠正我,如果我错了,未初始化的变量将从0开始或为null或''

所以我假设startDate = 10000和endDate 72359

btw为什么你选择这种数组(作为int或字符串值?)为什么第一个值是白天?不是日期的例子:
010000 - &gt;日期00:00的日期 312359 - &gt;这个月的第31日23:59

但这取决于你:D

很抱歉,如果我错了,我只在大学学习算法课,那是5年前的事:D

答案 4 :(得分:0)

更好的方法可能是规范化您的数据,将所有星期几的值转换为相对于开始日期。像这样:

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;

我很确定这将按照书面形式运作。无论如何,这个概念更加清晰,可以进行多重比较。

答案 5 :(得分:0)

我发现的最简单的解决方案是: 表示x您的通用时间和S,E分别为开始时间和结束时间(0

dat %>%
  summarise_all(~mean(.) * 100) %>%
  gather(key, value) %>%
  separate(key, into = c("item", "column"), sep = "_") %>%
  spread(column, value)

如果x在开始时间和结束时间之间,则此函数返回TRUE,否则返回FALSE。 它还会照顾开始时间,而不是结束时间(例如,您从20:00开始工作并在04:00结束,23:13将返回TRUE)

我必须说,考虑到乘法,它在速度上可能不是最有效的,但绝对是最紧凑的(而且是恕我直言)

编辑: 我找到了一个更优雅,更有效的解决方案:

f(x) = [(x-S) * (x-E) * (E-S) < 0]

您可以将XOR替换为“不同”运算符(!=)

我解释一下: 第一个公式来自考虑关系不平等的研究: 如果S

f(x) = (x<S) XOR (x<E) XOR (E<S)

因此,如果x在S和E之间,则总数为负

如果S> E:

...............S.....E..........
(x-S)----------+++++++++++++++++
(x-E)----------------+++++++++++
(E-S)+++++++++++++++++++++++++++
total++++++++++------+++++++++++

因此,如果x大于S或小于E,则总数为负

要得出最终方程,请用3个项分解第一个公式:

...............E.....S..........
(x-S)----------------+++++++++++
(x-E)----------+++++++++++++++++
(E-S)---------------------------
total----------++++++-----------

这些术语的乘积只有在全部为负数(true,true,true)或只有一个为负数而另一个为正数(true,false,false,但顺序无关紧要)时才为负数 因此,可以通过

解决问题
(x-S)<0 => x<S
(x-E)<0 => x<E
(E-S)<0 => E<S

这些解决方案可以应用于周期系统的任何类似问题,例如检查角度x是否在由两个角度S和E形成的圆弧内。 只要确保所有变量都在0和系统周期之间即可(圆弧为2PI,圆形为24h,小时为24 * 60 * 60,以秒为单位.....等等)< / p>