特定の日付/時刻が2つの日付/時刻のペアの間にあるかどうかを判断するアルゴリズム
-
10-07-2019 - |
質問
異常な方法で保存された1週間の範囲の日付の配列があります。
日付は次の数値形式で保存されます:12150
左から右へ:
1桁目は日を表します:1 =日曜日、2 =月曜日、3 =火曜日、....、7 =土曜日
次の2桁は24時間制の時間を表します:00 =真夜中、23 =午後11時
次の2桁は分を表します: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;
}
}
解決
方法について
const int MAX = 72460; // Or anything more than the highest legal value
inRange = (MAX + inputDate - startDate) % MAX <
(MAX + endDate - startDate) % MAX;
もちろん、これはすべての日付が整形式であることを前提としています(仕様による)。
これは、開始が<!> quot; after <!> quot;の場合に対応します。終わり。 (たとえば、開始が水曜日で終了が月曜日の場合、金曜日は範囲内です)
表示には数秒かかる場合があります(通常、読みやすさが最も重要であるため、おそらく良くありません)。しかし、うまくいくと思います。
基本的なトリックは次のとおりです。
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の値は実際には問題ではないため(これは最大の整形式の値を超えている限り)、自由に実行できます計算を簡単にするものを選択してください。
(もちろん、本当に必要な場合は、<
を<=
に置き換えることができます)
他のヒント
その形式の日付には論理エラーがあります。月と年の情報が欠落しているため、どの暦日が欠落しているかを知ることはできません。例えば50755は2009年3月12日木曜日かもしれませんが、ちょうど1週間前、または18週間先になるかもしれません。その形式の any の日付が他の2つの日付の any の間にある場合、100%確信することはできません。
ここでは、内側のif
の条件が真になることはありません。endDate < startDate
:
if (endDate < startDate) {
if((inputDate + 72359) > startDate &&
(inputDate + 72359) < endDate) {
// never reached
inRange = yes;
}
最初の部分は常に真であり、2番目の部分はinputDate < endDate
とまったく同じであるため、次の場合も最適化できません:
if((inputDate + 72359) > startDate &&
(inputDate + 72359) < (endDate + 72359))
次のようなものが欲しいと思います:
if (startDate < endDate)
inRange = (startDate < inputDate) && (inputDate < endDate);
else
inRange = (startDate < inputDate) || (inputDate < endDate);
範囲内で本当に必要な場合は、<!> gt; =および<!> lt; =を使用する必要があります
この日付10000または72359を選択すると、これをどのように処理しますか?範囲内かどうか
また、初期化していないのでstartDateとendDateの値を知りませんでした。間違っていたら修正してください。初期化されなかった変数は0またはnullまたは ''
で始まります。そのため、startDate = 10000およびendDate 72359を想定しています
ところで、なぜこの種の配列を(intまたはstring値として?)選ぶのでしょうか?なぜ最初の値はdayでしたか?日付ではない例:
010000-<!> gt;月の1日00:00
312359-<!> gt;月の31日23:59
しかし、それはあなた次第です:D
ごめんなさい、私が間違っていたら、大学でのみアルゴリズムクラスを取りましたが、それは5年前でした:D
より良いアプローチは、データを正規化して、すべての曜日の値を開始日からの相対値に変換することです。このようなもの:
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;
これは書かれた通りに機能すると確信しています。いずれにせよ、概念は複数の比較よりも簡潔です。