- 2006年以前
- 4月第1日曜日~10月最終日曜日
- 2007年以降
- 3月第2日曜日~11月第1日曜日
ある日がサマータイム期間に入っているかどうかを判定するためには、第n日曜日以降なのかどうかを調べる必要があります。
Java ならこうするだけなのですが、今回は MetaTrader での実現を考えました。MetaTrader ではサマータイム情報を持っていないため、算出してみようという話です。
課題設定
- 入力
- $Y$ (1970〜): 判定対象の年
- $M$ (1〜12): 判定対象の月
- $D$ (1〜31): 判定対象の日
- $n$ (1〜5): 基準を第$n$日曜日とする
- 出力
- 判定対象の日付が第$n$日曜日以降であれば$true$, 異なれば$false$
アルゴリズム
すぐに思い付く方法は、- $Y, M$ から月初日の曜日を算出する
- そこから、第$n$日曜日が何日かを算出する
- それと$D$を比較する
となるかと思います。
しかし、第$n$日曜日の日付を算出しなくても、もっと直接的に評価できます。
- $Y, M, D$から曜日 $W (日: 0, 月: 1, \cdots, 土: 6)$を算出する
- $D - W \ge 7(n-1)+1 $ ならば第$n$日曜日以降と判定
ちなみに Java での判定ロジックも追ってみましたが、同様の考え方になっていました。
バリエーション
最終日曜日なら、$ 7(n-1)+1 $の代わりに $月末日 - 7 + 1$ となります。月末日は求めないといけません。日曜日以外なら、$+1$ を $+2, +3, \cdots, +7$ とすれば良いでしょう。実装例 (MetaTrader4)
では、このロジックを使って、MetaTrader4 でサマータイム判定ロジックを組んでみます。
bool IsNewyorkSummerTimeSeason(datetime dt) {
int y;
switch (TimeMonth(dt)) {
case 1:
case 2:
return(false);
case 3:
y = TimeYear(dt);
if (y < 2007 || (y >= 2007 && TimeDay(dt) - TimeDayOfWeek(dt) < 8)) {
return(false);
}
return(true);
case 4:
if (TimeYear(dt) < 2007 && TimeDay(dt) - TimeDayOfWeek(dt) < 1) {
return(false);
}
case 5:
case 6:
case 7:
case 8:
case 9:
return(true);
case 10:
y = TimeYear(dt);
if (y >= 2007 || (y < 2007 && TimeDay(dt) - TimeDayOfWeek(dt) < 25)) {
return(true);
}
return(false);
case 11:
if (TimeYear(dt) >= 2007 && TimeDay(dt) - TimeDayOfWeek(dt) < 1) {
return(true);
}
case 12:
return(false);
}
return(false);
}
9、14、25、30行目で、今回のロジックを使っています。25行目は10月の最終日曜日判定です。10月末は31日と分かっているので、固定値で25と書けます。