2つの日付間の日数を数えるアルゴリズムを作成しようとしています。 2012年3月1日から2012年3月2日まで。
正解は何ですか、または最も人気のある選択肢は何ですか?私が使用するものでなければなりませんか?
この場合、比較している両方の日付を含めないと、日数は0になります。そのうちの1つを含めると、日数は1になります。両方を含めると、日は2になります。
最初に、両方の日付が同じ日である場合、アプリケーションで何が意味がありますか?私の意見では明白な答えは0であり、それがあなたの答えでもある場合、論理的な結論は、1日だけ異なる日付を2ではなく1にマッピングすることです。1日だけ異なる日付を2にマッピングすると、ギャップが生じます。と一致しない日付をマッピングする方法はありません。1。数学的な観点から、ギャップがない場合、より一貫性があると感じます。
1日離れているので、1と答えます。しかし、これに対する正しい答えはありません。それは、達成したいことの要件によって異なります。
用語と文脈の問題だと思います。
間の日数が範囲を除外する場合、2つの日付間の日数は0になります。これが必要な場合はいつでも。
日付の違い、つまり、終了日に到達するために開始日に何日追加する必要があるか:1。
または、範囲を含む日付間隔(例:開始日から終了日までの休暇日数は?ここでの答えは2です。
ジレンマの核心は、操作に「2つの日付間の日数を計算する」という名前を付けたことです。明らかに3/1/12と3/2/12の間にはゼロ日がありますが、それはおそらく、間違った計算を行うのではなく、間違った計算に名前を付けたことを意味します。
すべての例外があるため、日付の計算は非常にトリッキーです。そのため、要件の定義には本当に厳密でなければなりません。たとえば、「今マイナス1日」は何に変換されますか? 24時間前ならいつでもという意味かもしれませんが、ほとんどのアプリケーションではそれは間違いだと思います。確かに、ほとんどの日は24時間ですが、夏時間では1日は23時間、1日は25時間です。日曜日の正午なら、マイナス1日は、何時間前でも土曜日の正午を意味します。うるう秒とそれらがもたらすすべての問題、およびすべての算術IDとプロパティが保持されることを確認することで続行できますが、これはおそらく、やりたいことよりも多くの作業です。
一般的に、カレンダーの日付計算を行う場合、人々は「日付の違い」に関心があります。これは、日付が印刷された紙のカレンダーを想像し、開始日にコインや石などのマーカーを置くことで視覚化できます。マーカーをすぐ次の日付に移動することのみが許可されている場合、終了日までに何回移動する必要がありますか?それが、2つの日付の違いです。
ただし、もう1つの実用的な考慮事項は、アプリケーションに本当に終了日が含まれているかどうかです。たとえば、保険契約では、終了日を含めないのが一般的です。ポリシーの有効期限は、終了日の午前12時1分です。明日で期限が切れるポリシーを購入した場合、1日未満で十分です。一方、カリフォルニアでは、「家賃を支払うか辞めるための3日前の通知」退去通知は、あなたが外に出るのに3日以上かかります。通知が家賃を支払うために提供された後、あなたは3営業日の終わりまで持っています。したがって、月曜日が休日でない限り、水曜日+ 3日は実際には月曜日です。月曜日が休日である場合、火曜日であり、いずれにしても最終日全体を取得するため、家主は今日>水曜日+ 3日、つまり火曜日または水曜日まで続行できません。したがって、簡単な計算ではありません。
良いニュースは、頻繁に表示されるため、計算に使用できるライブラリがあり、実際の状況では、これらの種類の混乱のみを解消するために日付計算をどのように実行するかが適切に定義されていることです。
したがって、宿題を実際に行い、話している間隔を正しく指定する必要があります。
結局のところ、これに対する正しい答えは、ビジネス要件の状態が何であれ、です。
ただし、日付と時間を日付間で処理する場合、日付としてのみ(つまり、時間部分なしで)表現される日付はimplicitly日付の終わり(真夜中)に00:00
を追加します。
次に、2つの日付/時刻の間に何分分の差があるかを計算します。したがって、あなたの例を使用すると(ここでは米国の日付形式を想定しています)、2/1/2012 00:00
に到達するまでに、一度に3/1/2012 00:00
に何分追加する必要がありますか?
それが終わったら、分を時間に、次に日に変換し(60で割り、結果を24で割ります)、2つの日付の間の日数がわかります。
これを使用すると、2/1/2012 00:00
と3/1/2012 00:00
の間に1日あることがわかります。これは、論理的であり、この分野のほとんどの人々とこの分野でよく使用される関数を設計する人々の一般的な考え方(つまり、 JavaのJava.util.Date
または.NETのSystem.DateTime
など)
両方の日付、それはユーザーが期待するものだから(ほとんどの場合)
私は、日付を取り巻くロジックとエンティティの期限切れを処理する必要があったいくつかのプロジェクトに取り組んできました。そして、いくつかの落とし穴があります。
これらの落とし穴の本質は、プログラマーにとって意味のあることは、アプリケーションを使用する人々にとって必ずしも意味のあることではないということです。
ビジネスの人々は通常、次のようなことを言うでしょう、これは7月1日から31日までアクティブです。つまり、両方の日付が含まれているということです。つまり、30日間ではなく31日間アクティブである必要があります。しかし、それは通常の算術規則に反しています。
したがって、エンドユーザーの観点から質問をすると、私の経験では、日数を計算するときに両方の日付を含める必要があるという答えになります。
私の実務経験からのいくつかの例:
私はオンライン求人掲示板の作成に携わっていましたが、一部のエンティティタイプ(ジョブの有効期限、サブスクリプションなど)の終了日に関して多くの問題がありました。これらは、このエンティティがまだ有効であった最終日として指定されます。これは、データベースに保存されたものです。ただし、コードで意味があるのは、エンティティが状態を変更する正確な時刻、つまり次の日の00:00にあることです。これは非常に複雑なドメインロジックにつながります。
ある時点で、システム全体をリファクタリングして、データベースのすべてのEndDateに1日を追加し、ロジックをプレゼンテーションレイヤーに移動して、ユーザーに提示される実際の日付は、データベース内の日付の前日である必要があります。これにより、アイテムの有効期限に関するドメインロジックがはるかに明確になります。
日付/エンティティの有効期限ロジックが重要な場所で作業した次のプロジェクトを実行するときに、オーバーロードを含むこれらのルールを含む特定のDateデータ型を作成しました組み込み演算子DateTimeを使用した比較演算子、算術演算子など。これにより、ドメインモデルがより適切に反映されるため、コードがさらに単純になります。プレゼンテーションレイヤーがすべての終了日から1日を引くという要件が削除され、誰かがこれを実装するのを忘れるリスクもなくなりました。
状況を考慮する必要があります。私の勤務スケジュールが月曜日から金曜日までである場合、私が4日間しか現れない場合、上司は少し不快になります。
これは、このコンテキストでは、月曜日は月曜日だけでなく月曜日8:30を表し、金曜日は金曜日17:00を表すためです。
ある日付D1と別の日付D2の間の日数NDは、次のようになります。
ND = D2 - D1
または:
D1 + ND = D2
それはコンテキストに大きく依存しますが、私の意見では、明白な答えはカウントに日付の1つを含めることです。
どちらもカウントしていないとしましょう。また、ユーザーが入力した2つの日付の違いを判別するためのアルゴリズムを使用するアプリケーションがあるとします。この場合、3/1/2012と3/2/2012の差は0です。2つの日付が等しいとユーザーが想定しても問題ありませんか?それが0が示唆することだからです。それらの間に違いはありません->>それらは等しいです。それはおそらく間違っています...
次に、両方を数えると仮定しましょう。この場合、差は2未満にはなりません。2012年3月1日から2012年3月2日までの間に2日間ありますか?確かに違います。 3/1/2012と3/1/2012の間はどうですか?もう一度:いいえ。
入力として日付のみがあり、時間がないという事実を踏まえて、私は次のようなアルゴリズムを実行します。
最初に述べたように、これは最終的にはビジネス要件に依存します。