2020/05/05

日付処理 - MetaTrader - ニューヨークサマータイム判定 (第n日曜日以降判定)

ニューヨークのサマータイム期間は、以下のようになっています。

  • 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$日曜日以降と判定
この方が若干計算量が少ないですよね。もし $W$ が別の用途で必要だったりすると、なお有利です。月初日の曜日よりは用途がありそうです。

ちなみに 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と書けます。