日付範囲の日付の年を無視するためのベストプラクティス
質問
季節に関するいくつかの情報をモデル化し、開始日/終了日に基づいて年に依存しない方法でそれらを追跡する必要があります。つまりユーザーが夏を、たとえば5月15日から9月10日の間と定義できるようにする必要があります。
isThisDateInSeason型の多くのチェックを行う必要があります)。すべての日付操作関数(つまり、日付、カレンダー)は、有効な日付、つまり年情報を含む場合にのみ機能するようです。
これを行う方法に関するベストプラクティスはありますか?私はそれを行うためのたくさんのハック方法を考えることができます(つまり、月と日を保存するか、日付を保存し、比較できるように基準年に持って行くだけです)が、より良い方法があるかもしれません。
これをJavaまたはGroovyで書いています。
Joda-Time ライブラリはここで役立ちますか?経験はありませんが、はるかに柔軟性があるようです。
この質問を見つけて、日付からシーズンですが、それは月に焦点を当てており、日付を含めるために、より柔軟性が必要です。
解決
各ユーザーが独自のデータを所有している場合(つまり、季節を指定してから独自の情報を入力する場合)、季節の一部としてデータを保存できますが、後のシナリオはそう感じます季節を異なる方法で定義する多数のユーザー間で共有データを使用します。
うるう年は予期しない問題を引き起こす可能性があるため、日付を「正規化」するように非常に注意する必要があります。つまり、うるう年ではない2月29日を設定しようとすると、問題/例外が発生します。
以下をまとめましたが、残念ながらそのc#ですが、概念は同じです。実際にコードをテストしましたが、psudoコードと同じように役立つ場合があります。
public class SeasonChecker
{
public enum Season {Summer, Autumn, Winter, Spring};
private List<SeasonRange> _seasons = new List<SeasonRange>();
public void DefineSeason(Season season, DateTime starting, DateTime ending)
{
starting = starting.Date;
ending = ending.Date;
if(ending.Month < starting.Month)
{
// split into 2
DateTime tmp_ending = new DateTime(ending.Year, 12, 31);
DateTime tmp_starting = new DateTime(starting.Year, 1, 1);
SeasonRange r1 = new SeasonRange() { Season = season, Starting= tmp_starting, Ending = ending };
SeasonRange r2 = new SeasonRange() { Season = season, Starting= starting, Ending = tmp_ending };
this._seasons.Add(r1);
this._seasons.Add(r2);
}
else
{
SeasonRange r1 = new SeasonRange() { Season = season, Starting= starting, Ending = ending };
this._seasons.Add(r1);
}
}
public Season GetSeason(DateTime check)
{
foreach(SeasonRange range in _seasons)
{
if(range.InRange(check))
return range.Season;
}
throw new ArgumentOutOfRangeException("Does not fall into any season");
}
private class SeasonRange
{
public DateTime Starting;
public DateTime Ending;
public Season Season;
public bool InRange(DateTime test)
{
if(test.Month == Starting.Month)
{
if(test.Day >= Starting.Day)
{
return true;
}
}
else if(test.Month == Ending.Month)
{
if(test.Day <= Ending.Day)
{
return true;
}
}
else if(test.Month > Starting.Month && test.Month < Ending.Month)
{
return true;
}
return false;
}
}
}
上記のコードは、シーズンが同じ月に開始および終了しないことを前提としていることに注意してください-かなり安全だと思います!
他のヒント
私はあなたがあなた自身のDateRangeクラスをロールする必要があると思いますが、これはあなたが既にそれを行う巧妙なユーティリティがあることを願うようなとても一般的な問題です。季節を扱う際の一般的なポイントとして、地理も考慮する必要があります。これは人生を本当に難しくします。オズではアメリカの逆なので、夏は11月から2月までです。
データはどこにありますか?データベース内にある場合は、日付のテーブル(OLAPの時間ディメンションなど)を作成することを検討します。その後、いくつかのTime Dimensionの例で、四半期が財務四半期の場合のように、季節の列を計算できます。 (これは、季節が変わらず、日付が固定されていることを前提としています)。
「if in date in season」」のすべて型チェックが事前に構築され、季節を計算するコストを実行時間ではなくセットアップ時間にプッシュします。
編集:ユーザーが設定可能なシーズンの日付に関するコメントを見ました。時間ディメンションを含むデータベースで結合を行うことができるため、これは引き続き機能します。これにより、Javaよりもデータセットを簡単に操作できます。