English

MQL5の書き方(for MQL4デザイナー)

 

2024.04

林貴晴/AMSER Inc.

夏時間の判定方法

サーバー時間をコントロールする上で夏時間の判定は不可欠ですが、MQL5でのプログラミングではこれが最も高度な技術の一つに数えられます。
本記事では、一般的な方法と林式を用いた夏時間の判定方法を詳しく解説します。

 

アメリカの夏時間

サーバー時間として広く使用されているGMT+2/+3は、アメリカの夏時間のスケジュールに基づいています。この時間帯では、週に5本の日足が形成され、日足の時間が一定であることが特徴です。アメリカの夏時間は3月の第2日曜日から11月の第1日曜日まで適用されています。この夏時間スケジュールは2007年から開始されました。それ以前は、夏時間は4月の最後の日曜日から10月の最後の日曜日まででしたので、この変更点に注意する必要があります。

 
 

一般的な夏時間の判定方法

夏時間の判定の一般的な月、日、曜日を用いる方法を紹介します。
3月と11月は夏時間、標準時間に変わりますが、変更する日付が変動するため、日と曜日を用いて判定します。それ以外の月は月単位で判定します。
夏時間への変更時間はサーバーの設定時間によって異なりますが、変更は日曜日に行われるため特に考慮する必要はありません。

 
月による判定

1月、2月、12月:すべて標準時間
4月から10月:すべて夏時間

 
夏時間と標準時間が含まれる月

3月と11月は日と曜日によって条件を検討する必要があります。
閏年(うるうどし)も条件に変更はありません。
また、条件分岐を減らすためにサーバーの動いていない土日は考慮していません。

〇3月の条件
3月8日までは標準時間
3月9日 月曜日は夏時間
3月10日 月、火曜日は夏時間
3月11日 月、火、水曜日は夏時間
3月12日 月、火、水、木曜日は夏時間
3月13日以降は夏時間
4年に一度の閏年でも条件は変わりません。
※土日はサーバーが動いていない為、無視することができます。

表1)青色;標準時間 橙色:夏時間

 

〇11月の条件
11月1日 夏時間
11月2日 火、水、木、金曜日は夏時間
11月3日 水、木、金曜日は夏時間
11月4日 木、金曜日は夏時間
11月5日 金曜日は夏時間
11月6日以降 標準時間

表2)青色;標準時間 橙色:夏時間

 

一般的な方法では、夏時間と標準時間の判定には多くの条件分岐が含まれており、特に3月と11月には複雑なルールを適用する必要があります。適切に時刻を管理するためには、これらの条件を正確に理解し、適用することが重要です。

 

林式判定方法
前述したように、従来の一般的な方法では多くの条件分岐が必要となり、これが運用時のPCやVPSの負荷、さらにはバックテストや最適化の時間に影響を与える可能性があります。 そこで、MqlDateTime構造体のday_of_yearと、day_of_weekを利用した、条件分岐を効果的に減らす方法を紹介します。

day_of_year  年初からの通算日数(1月1日は1、12月31日は365または366)。
day_of_week  週の曜日を数字で表す(日曜が0、土曜が6)

林式ではday_of_year – day_of_weekの計算結果を用いて、夏時間か標準時間かを判定します。

day_of_year、day_of_weekは共に毎日1ずつ数字が増えていきますので、day_of_year – day_of_weekの計算結果は変化しません。しかし、日曜日にはday_of_weekが0に戻るため計算結果は7増えます。
つまりday_of_year – day_of_weekは日曜日を基準に数値が増加します。

この特性を利用すると、非閏年の夏時間適応日はday_of_year – day_of_weekが67から305の間、
閏年では68から306が夏時間の適応期間となります。

夏時間判定コード

                    MqlDateTime MqlTime;
TimeCurrent(MqlTime);
long YearWeekOffset = MqlTime.day_of_year - MqlTime.day_of_week;
//非閏年
if(MathMod(MqlTime.year, 4) != 0 &&
      67 <= YearWeekOffset &&
      YearWeekOffset <= 305)
   Print("夏時間");
//閏年
if(MathMod(MqlTime.year, 4) == 0 &&
      68 <= YearWeekOffset &&
      YearWeekOffset <= 306)
   Print("夏時間");
                    
 

MqlTimeをMqlDateTime構造体として宣言し、現在の時間を代入しています。
YearWeekOffsetを宣言しDay_of_year – day_of_weekの値を代入します。
MqlTime.yearを4で割った余りが0でない時、すなわち非閏年でYearWeekOffsetが66から305の時は「夏時間」をPrint()で出力します。

同様に閏年の時も67から306の時に「夏時間」を出力します。

※閏年の条件は100の倍数でなく400の倍数である時とそれ以外の4の倍数の年ですが、100年単位の条件になるのは120年以上前か70年以上後であるためここでは4の倍数として計算します。

時間の取り扱い、管理はプログラマーにとって大きな課題の一つです。特に変動が多く複雑な夏時間の判定を簡潔に行うことは、運用時のシステム負荷を大幅に軽減し、コーディング中のエラー発生率を低下させます。このような効率化は、プログラムのパフォーマンス向上と維持管理の簡素化に寄与し、開発者にとってもエンドユーザーにとっても大きなメリットをもたらします。さらに、時間に関連するバグは発見が難しいとされています。シンプルで効率的なアプローチを理解し、適応することで、より信頼性の高いシステムを構築しましょう。

執筆者紹介
林貴晴

林 貴晴(AMSER株式会社代表取締役)

内資系薬品会社で約10年勤務の後、
外資系製薬会社(現IQVIA及びGSK)で合計約10年を勤務
その後EA AMSERを開発し、その成績を評価され、株式会社ゴゴジャンの部長として抜擢。
現在はAMSER株式会社代表取締役。