【完全保存版】MQL4で夏時間・冬時間を正しく判定する方法|初心者向けハードコード版 & 実務向け動的計算法

夏時間と冬時間を対比したデグーキャラクターのイラストで、MQL4のサマータイム判定とGMT変換を解説する記事用アイキャッチ画像。
EAサンプル・ノウハウ
記事内に商品プロモーションを含む場合があります
スポンサーリンク

「MT4のEAで時間条件を組みたいけれど、夏時間(サマータイム)と冬時間の切り替えが難しい…
「GMT時間と日本時間の変換が合わず、バックテストでズレが出る…」

そんな悩みを抱えるEA初心者に向けて、この記事ではMQL4で夏時間・冬時間を正しく判定する方法をわかりやすく解説します。
初心者でも使いやすいハードコード版と、実務で活躍する動的計算法(推奨)の両方を掲載しているので、レベルに合わせてそのままコピペで使えます。

JST⇔GMTの変換関数や、EA内での実装例まで網羅した完全保存版としてお役立てください。

MQL4では「夏時間・冬時間の処理」がなぜ重要か?

MT4/EAは国内業者の多くがGMT+2(冬時間) / GMT+3(夏時間)で動いています。
この切り替えを無視すると、以下のような不具合が発生します。

  • 指定時刻のエントリーが1時間ズレる
  • バックテストの整合性が崩れる
  • 不要な時間帯にポジションを持ってしまう

特に「○時〜○時だけエントリーする」などの時間条件付きEAでは、正確な判定が必須です。

どちらのコードを使うべき?(初心者 vs 中級者)

▼ まずどちらのコードを使うべきか?
・まず動かしてみたい初心者 → ハードコード版(旧コード)
・長期運用EA / バグを避けたい → 動的計算法(新コード/推奨)

初心者向け|そのまま使えるハードコード版(旧コード)

📌 ハードコード版の特徴(簡単まとめ)
・メリット:書いてある日付を読むだけで理解しやすい
・デメリット:2041年以降は自分で追記が必要

まずは初心者向けとして、2004–2040年の期間をすべて明記した「ハードコード版」です。
年ごとの夏時間期間を一覧で書いているだけなので、視覚的に理解しやすいというメリットがあります。
一方で、2041年以降は自分で追記する必要があるため、利便性は低めです。

ハードコード版サンプルソース

//+------------------------------------------------------------------+
//|【関数】サマータイム確認 
//| 
//|【引数】 なし
//| 
//|【戻値】True:サマータイム
//|【備考】3月第2日曜日~11月第1日曜日までをサマータイムとする
//|
bool IsSummerTime(){
   
   switch(Year()){
      case 2004: if(StringToTime("2004.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2004.11.7"))return true; break;
      case 2005: if(StringToTime("2005.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2005.11.6"))return true; break;
      case 2006: if(StringToTime("2006.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2006.11.5"))return true; break;
      case 2007: if(StringToTime("2007.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2007.11.4"))return true; break;
      case 2008: if(StringToTime("2008.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2008.11.2"))return true; break;
      case 2009: if(StringToTime("2009.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2009.11.1"))return true; break;
      case 2010: if(StringToTime("2010.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2010.11.7"))return true; break;
      case 2011: if(StringToTime("2011.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2011.11.6"))return true; break;
      case 2012: if(StringToTime("2012.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2012.11.4"))return true; break;
      case 2013: if(StringToTime("2013.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2013.11.3"))return true; break;
      case 2014: if(StringToTime("2014.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2014.11.2"))return true; break;
      case 2015: if(StringToTime("2015.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2015.11.1"))return true; break;
      case 2016: if(StringToTime("2016.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2016.11.6"))return true; break;
      case 2017: if(StringToTime("2017.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2017.11.5"))return true; break;
      case 2018: if(StringToTime("2018.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2018.11.4"))return true; break;
      case 2019: if(StringToTime("2019.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2019.11.3"))return true; break;
      case 2020: if(StringToTime("2020.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2020.11.1"))return true; break;
      case 2021: if(StringToTime("2021.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2021.11.7"))return true; break;
      case 2022: if(StringToTime("2022.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2022.11.6"))return true; break;
      case 2023: if(StringToTime("2023.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2023.11.5"))return true; break;
      case 2024: if(StringToTime("2024.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2024.11.3"))return true; break;
      case 2025: if(StringToTime("2025.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2025.11.2"))return true; break;
      case 2026: if(StringToTime("2026.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2026.11.1"))return true; break;
      case 2027: if(StringToTime("2027.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2027.11.7"))return true; break;
      case 2028: if(StringToTime("2028.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2028.11.5"))return true; break;
      case 2029: if(StringToTime("2029.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2029.11.4"))return true; break;
      case 2030: if(StringToTime("2030.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2030.11.3"))return true; break;
      case 2031: if(StringToTime("2031.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2031.11.2"))return true; break;
      case 2032: if(StringToTime("2032.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2032.11.7"))return true; break;
      case 2033: if(StringToTime("2033.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2033.11.6"))return true; break;
      case 2034: if(StringToTime("2034.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2034.11.5"))return true; break;
      case 2035: if(StringToTime("2035.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2035.11.4"))return true; break;
      case 2036: if(StringToTime("2036.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2036.11.2"))return true; break;
      case 2037: if(StringToTime("2037.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2037.11.1"))return true; break;
      case 2038: if(StringToTime("2038.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2038.11.7"))return true; break;
      case 2039: if(StringToTime("2039.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2039.11.6"))return true; break;
      case 2040: if(StringToTime("2040.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2040.11.4"))return true; break;      
   }
   return false;
}

『3月第2日曜日~11月第1日曜日までがサマータイム』なので2004年以前や2040年以降もカレンダーを見ながら同じ感じで追記してもらっても問題ありません。

このIsSummerTime()関数は、コメントの通り引数無し、戻り値は(True:サマータイム False:冬時間)という形になります。

ハードコード版:EA内での使用方法(OnTickへの実装例)

具体的な使用例を記載します。

//取引時間確認(サマータイム時)
if(IsSummerTime()==true){
    //夏時間の処理
    ・・・
}else{
    //冬時間の処理
    ・・・
}

これで、夏時間・冬時間の判定が可能です。

スポンサーリンク

中級者向け|動的計算で自動判定する(新コード|推奨)

下サンプルソース(MQL4)の関数になります。そのままコピペでお使いください。正しく時間を変換するには、サマータイムを判定する処理も必須なので合わせてご紹介します。
※標準時は「GMT+2」、夏時間は「GMT+3」とする

サマータイム判定するサンプルソース


//+------------------------------------------------------------------+
//| 【関数】サマータイム判定(米国ルール)                             |
//| 3月第2日曜~11月第1日曜までをサマータイムとする                   |
//+------------------------------------------------------------------+
bool IsSummerTime()
{
   int year = TimeYear(TimeCurrent());
   
   // 3月第2日曜
   datetime marchFirst = StringToTime(StringFormat("%04d.%02d.01 00:00", year, 3));
   int marchWeekday = TimeDayOfWeek(marchFirst); // 0=日曜
   int marchDaysToFirstSunday = (7 - marchWeekday) % 7;
   datetime summerStart = marchFirst + (marchDaysToFirstSunday + (2 - 1) * 7) * 86400;
   
   // 11月第1日曜
   datetime novFirst = StringToTime(StringFormat("%04d.%02d.01 00:00", year, 11));
   int novWeekday = TimeDayOfWeek(novFirst);
   int novDaysToFirstSunday = (7 - novWeekday) % 7;
   datetime summerEnd = novFirst + (novDaysToFirstSunday + (1 - 1) * 7) * 86400;
   
   return (TimeCurrent() >= summerStart && TimeCurrent() < summerEnd);
}

この関数は引数はなく、呼び出すことで現在がサマータイムであれば「true」そうでなければ「false」が返ってきます。3月第2日曜と11月第1日曜を算出しサマータイムを判定している感じですね。

以降の「GMTから日本時間に変換する」「日本時間からGMT時間に変換する関数でも使っていますのでセットでお使いください。

GMT時間を日本時間に変換するサンプルソース

//+------------------------------------------------------------------+
//|【関数】GMTを日本時間(JST)に変換                                   |
//|                                                                  |
//|【引数】GMT_HOUR: GMT時間(基本はGMT+3)                                     |
//|【戻値】cTime: 日本時間                                           |
//+------------------------------------------------------------------+
int ChangeGMTtoJP(int GMT_HOUR)
{
   int diff = IsSummerTime() ? +6 : +7;
   int cTime = (GMT_HOUR + diff) % 24;
   return cTime;
}

GMT時間をこの関数に渡すことで、日本時間が返ってくるという関数です。サマータイム状況により時間は変わりますので9行目にはサマータイムを判定する関数「IsSummerTime()」を使っています。この関数は前述しているのでセットでお使いください。

日本時間をGMT時間に変換するサンプルソース

//+------------------------------------------------------------------+
//|【関数】日本時間(JST)をGMTに変換                                   |
//|                                                                  |
//|【引数】JP_HOUR: 日本時間                                           |
//|【戻値】cTime: GMT時間(基本はGMT+3)                                    |
//+------------------------------------------------------------------+
int ChangeJPtoGMT(int JP_HOUR)
{
   int diff = IsSummerTime() ? -6 : -7;  
   int cTime = (JP_HOUR + diff + 24) % 24;  // マイナスを防ぐため+24
   return cTime;
}

日本時間をこの関数に渡すことで、GMT時間が返ってくるという関数です。サマータイム状況により時間は変わりますので9行目にはサマータイムを判定する関数「IsSummerTime()」を使っています。この関数は前述しているのでセットでお使いください。

新コード:EA内での使用方法(OnTickへの実装例)

具体的な使用例を記載します。

void OnTick() {

   string daysv = StringSubstr(TimeToStr(TimeCurrent(), TIME_DATE | TIME_MINUTES), 0, 10); 
   
   Print(daysv,"はサマータイム:",IsSummerTime());

   int GMT_h = Hour();
   int JST_h = ChangeGMTtoJP(GMT_h);
   
   Print("日本時間:",JST_h,"時");
   Print("GMT時間:",ChangeJPtoGMT(JST_h),"時");
 

}
//上記3つの関数は↓に貼り付けてください

こんな感じで日付を変換できるので、用途に応じてお使いください。

【完全保存版】MQL4で夏時間・冬時間を正しく判定する方法|初心者向けハードコード版 & 実務向け動的計算法

サマータイム判定や、切り替わりでしっかり時間も変換されていますね!

❓ 夏時間・GMTに関するよくある質問まとめ【MQL4対応】

💬 夏時間の扱い、GMT+2/GMT+3の理由、バックテストの時間ズレなど、EA開発でよくある疑問をまとめました。

夏時間と冬時間の判定は毎年変わる?

はい。米国のサマータイムは「3月第2日曜〜11月第1日曜」で毎年日付が変わります。
MT4のサーバー時間は基本的にこの米国ルールを採用しているため、毎年動的に判定しないと誤差が出ます。

国内MT4業者はなぜGMT+2/GMT+3なのか?

米国市場の営業時間に合わせるためです。
冬時間はGMT+2、夏時間はGMT+3が採用されており、これにより1日のローソク足がきれいに5本に揃います。
EAの時間条件もこのサーバー時間に従う必要があります。

バックテストで時間ズレが起きる理由は?

使用するヒストリカルデータのGMT設定と、EA側の時間変換ロジックが一致していないことが主な原因です。
サマータイム切り替えの判断を誤ると、バックテストでは1〜2時間のズレが発生します。

上記コードはMT5でも使える?

サマータイム判定ロジックそのものはMT5でも利用可能ですが、時間関数や構文が一部異なります。
MQL5用に置き換える必要がありますが、計算の考え方は同じです。

注意事項とまとめ

長期運用するEAを作る場合、サマータイムの正確な処理は欠かせません
特にエントリー時間・決済時間を条件に含むEAでは、時間のズレが動作ミスに直結します。

  • 初心者 → ハードコード版(旧)
  • 実運用・長期保守 → 動的計算法(新|推奨)

この記事のサンプルコードをそのまま組み込めば、サマータイムの誤差ゼロのEAを作ることができます。

🔗 関連記事(MQL4の便利関数)


コメント

タイトルとURLをコピーしました