1

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

日期以这种数字格式存储:12150

从左到右:

第一个数字代表日期: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;   
        }

}
4

6 回答 6

2

怎么样

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

这当然假设所有日期都格式正确(根据您的规格)。

这解决了开始在结束“之后”的情况。(例如,如果开始是星期三,结束是星期一,则星期五在范围内)

可能需要一秒钟才能看到(这可能不好,因为可读性通常是最重要的)但我认为它确实有效。

这是基本技巧:

传奇:

  0:最短时间
  M:最长时间

  S:开始时间
  1,2,3:输入时间测试点
  E:结束时间

SE => 不在范围内
  2 在范围内
  3 > E => 不在范围内

S > E 案例
                        0 米
  原版-1--E----2---S--3--
  加最大值 --------------------1--E----2---S--3--
  减去开始日期-----1--E----2---S--3--      
  % 最大 S--3--1--E----2----

  1 在范围内
  2 > E => 不在范围内
  3 在范围内

如果你真的想发疯(而且更难破译)

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

这应该稍微快一点(将模数换成按位和),我们可以这样做,因为 MAX 的值并不重要(只要它超过最大的格式良好的值),我们可以自由选择一个使我们的计算变得容易。

(当然,如果这是你真正需要的,你可以<用 a替换)<=

于 2009-03-12T05:52:37.030 回答
1

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

于 2009-03-12T05:56:50.703 回答
1

在这里,内部的条件if永远不会为真,因为endDate < startDate

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

以下 if 也不是最优的,因为第一部分始终为真,而第二部分与 相同inputDate < endDate

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

我想你想要这样的东西:

if (startDate < endDate)
  inRange = (startDate < inputDate) && (inputDate < endDate);
else
  inRange = (startDate < inputDate) || (inputDate < endDate);
于 2009-03-12T05:58:18.983 回答
0

如果你真的想要它在范围内,你应该使用 >= 和 <=

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

我也不知道 startDate 和 endDate 的值,因为您没有对其进行初始化,如果我错了,请纠正我,未初始化的变量将以 0 或 null 或 '' 开头

所以我假设 startDate = 10000 和 endDate 72359

顺便说一句,为什么您选择这种数组(作为 int 或字符串值?)为什么第一个值是 day?非日期示例: 010000
-> 日期 1 日 00:00
312359 -> 日期 31 日 23:59

但这取决于你:D

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

于 2009-03-12T06:04:51.870 回答
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;

我很确定这将按书面规定工作。无论如何,这个概念比多重比较更清晰。

于 2009-03-12T06:49:40.013 回答
0

我找到的最简单的解决方案是:表示 x 你的通用时间和 S,E 分别是开始和结束时间(0 < S,E < T):

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

如果 x 在开始时间和结束时间之间,此函数返回 TRUE,否则返回 FALSE。它还将处理大于结束时间的开始时间(即您从 20:00 开始工作并在 04:00 结束,23:13 将返回 TRUE)

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

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

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

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

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

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

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

如果 S > E:

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

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

为了达到最终方程,您将第一个公式分解为 3 项:

(x-S)<0 => x<S
(x-E)<0 => x<E
(E-S)<0 => E<S

这些项的乘积只有当它们都为负(真、真、真)或只有一个为负而另一个为正(真、假、假,但顺序无关紧要)时才为负,因此问题可以解决通过

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

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

于 2019-07-23T14:54:35.960 回答