他言語の実用モジュールをMQL5で実装する(第04回):Pythonのtime、date、datetimeモジュール
内容
はじめに
時間は私たちの生活における基本的な単位であり、この宇宙に存在するあらゆるものは時間によって測定されています。日常生活においては、目標の達成までの時間を測定したり、スマートフォンや時計などの時間管理デバイスを用いてタスクを監視し、管理しています。
アルゴリズム取引や取引全般においても、時間は依然として重要な要素となっています。私たちはしばしば時間に基づいて取引判断をおこない、その成果を日次、週次、月次といった単位で評価します。
MQL5には、時間の管理や評価をおこなうための組み込み関数が豊富に用意されており、アルゴリズム取引システムが現実の時間と同期できるようになっています。しかしながら、MQL5における時間や日付の扱いは比較的基本的で、場合によっては人間にとって直感的とは言えないことがあります。一方で、Pythonは、datetime、calendar、time、zoneinfoといった豊富なモジュールを提供しており、より高度で扱いやすい時間処理が可能です。

本記事では、こうしたPythonの機能に類似した時間処理モジュールを、MQL5で実装していきます。
timeクラス(モジュール)
まず、timeというクラスから始めます。このクラスは、Pythonにおいて時間を扱うための基本的な機能(メソッド)を提供します。
Pythonのドキュメントによると、
timeオブジェクトは、特定の日付に依存しない「1日の中のローカル時間」を表し、tzinfoオブジェクトによって調整されます。
class datetime.time(hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0)
すべての引数は省略可能です。tzinfoはNone、またはtzinfoのサブクラスのインスタンスである必要があります。他の引数は以下の範囲の整数でなければなりません。
- 0 <= hour < 24
- 0 <= minute < 60
- 0 <= second < 60
- 0 <= microsecond < 1000000
これらの範囲外の値が指定された場合、ValueErrorが発生します。デフォルト値は、tzinfoがNoneであることを除き、すべて0です。
Pythonにはdatetimeやdateなど、時間を扱うためのクラスが他にも存在します。しかし、timeモジュール内のtimeクラスは、日付を考慮せずに純粋に「時刻のみ」を扱うことに特化しています。これは、「その日の特定の時刻」を知りたい場合に対応するものです。
CTimeクラスでは、コンストラクタ内でユーザーが適切な値を渡しているかどうかを検証する必要があります。これはPythonの挙動と同様です。
class CTime { protected: uint m_hour; uint m_minute; uint m_second; uint m_millisecond; CTZInfo *m_tzinfo; public: //--- constructors CTime(void); CTime(const int hour, const int minute, const int second, CTZInfo *tzinfo=NULL, const int milliseconds=0); ~CTime(void); //--- A destructor
CTime::CTime(const int hour, const int minute, const int second, CTZInfo *tzinfo=NULL, const int milliseconds=0) { // --- Validate hour --- if(hour < MINHOUR || hour > MAXHOUR) { printf("CTime Error: hour (%d) out of range [%d..%d]. Defaulting to 0.", hour, MINHOUR, MAXHOUR); m_hour = 0; } else m_hour = hour; // --- Validate minute --- if(minute < MINMINUTES || minute > MAXMINUTES) { printf("CTime Error: minute (%d) out of range [%d..%d]. Defaulting to 0.", minute, MINMINUTES, MAXMINUTES); m_minute = 0; } else m_minute = minute; // --- Validate second --- if(second < MINSECOND || second > MAXSECOND) { printf("CTime Error: second (%d) out of range [%d..%d]. Defaulting to 0.", second, MINSECOND, MAXSECOND); m_second = 0; } else m_second = second; // --- Validate millisecond --- if(milliseconds < MINMILLISECOND || milliseconds > MAXMILLISECOND) { printf("CTime Error: millisecond (%d) out of range [%d..%d]. Defaulting to 0.", milliseconds, MINMILLISECOND, MAXMILLISECOND); m_millisecond = 0; } else m_millisecond = milliseconds; // --- Timezone info pointer --- m_tzinfo = tzinfo; }
クラスのコンストラクタが呼び出されると、渡された引数に基づいて内部変数が設定され、CTimeオブジェクトが生成されます。
tzinfoというオプション変数は、その時刻が属するタイムゾーン情報を保持します。
以下はCTimeクラスに含まれる主なメソッドです。
(a) fromisoformat
この関数は、有効なISO 8601形式のtime_string変数に対応するCTimeオブジェクトを返します。ただし、以下の例外があります。
- タイムゾーンのオフセットには小数秒を含めることができる
- 通常、日付と時刻の曖昧さを避けるために必要とされる先頭の「T」は必須ではない
- 小数秒は任意の桁数を取ることができる(6桁を超える部分は切り捨てられる)
- 時および分の小数表現はサポートされていない
CTime CTime::fromisoformat(string time_string) 使用例
void OnStart() { //--- CTime time; Print("Time: ",time.fromisoformat("04:23:01").__str__()); Print("Time: ",time.fromisoformat("T04:23:01").__str__()); Print("Time: ",time.fromisoformat("T042301").__str__()); Print("Time: ",time.fromisoformat("04:23:01.000384").__str__()); Print("Time: ",time.fromisoformat("04:23:01,000384").__str__()); Print("Time: ",time.fromisoformat("04:23:01+04:00").__str__()); Print("Time: ",time.fromisoformat("04:23:01Z").__str__()); Print("Time: ",time.fromisoformat("04:23:01+00:00").__datetime__()); }
出力結果は以下のとおりです。
OL 0 20:44:38.611 Time testing (XAUUSD,H1) Time: 04:23:01 IG 0 20:44:38.611 Time testing (XAUUSD,H1) Time: 04:23:01 KO 0 20:44:38.611 Time testing (XAUUSD,H1) Time: 04:23:01 EF 0 20:44:38.611 Time testing (XAUUSD,H1) Time: 04:23:01 GQ 0 20:44:38.611 Time testing (XAUUSD,H1) Time: 04:23:01 QI 0 20:44:38.611 Time testing (XAUUSD,H1) Time: 04:23:01 CP 0 20:44:38.611 Time testing (XAUUSD,H1) Time: 04:23:01 HJ 0 20:44:38.611 Time testing (XAUUSD,H1) Time: 1970.01.01 04:23:01
メソッド__str__()と__datetime__()は、CTimeオブジェクトに格納されている時刻をそれぞれ文字列とdatetime形式の値に変換します。
(b) strptime
この関数は、文字列形式の時刻をdatetime型に変換します。
datetime CTime::strptime(string timestr, string format)
使用例
void OnStart() { //--- Print("Time: ", CTime::strptime("00:00:01", "%H:%M:%S")); Print("Time: ", CTime::strptime("00,00,01", "%H,%M,%S")); Print("Time: ", CTime::strptime("00-00-01", "%H-%M-%S")); }
出力結果は以下のとおりです。
MD 0 20:37:49.509 Time testing (XAUUSD,H1) Time: 1970.01.01 00:00:01 IL 0 20:37:49.509 Time testing (XAUUSD,H1) Time: 1970.01.01 00:00:01 EE 0 20:37:49.509 Time testing (XAUUSD,H1) Time: 1970.01.01 00:00:01
(c) replace
この関数は、指定されたパラメータのみを変更した新しいCTimeオブジェクトを返します。 tzinfo=NULLを指定することで、タイムゾーン情報を持つ時刻から、変換をおこなわずにナイーブな時刻を生成することも可能です。
CTime CTime::replace(const int hour, const int minute=-1, const int second=-1, CTZInfo *tzinfo=NULL, const int millisecond=0) { //--- Modify only specified values int n_hour = int(hour<=-1?this.m_hour:hour); int n_minute = int(minute<=-1?this.m_minute:minute); int n_second = int(second<=-1?this.m_second:second); int n_millisecond = int(millisecond<=-1?this.m_millisecond:millisecond); //--- m_tzinfo = tzinfo; return CTime(n_hour, n_minute, n_second, m_tzinfo, n_millisecond); }
使用例
void OnStart() { CTime time(9, 48, 10, &tzinfo); Print(time.__str__()); time = time.replace(22); //replace the hour and assign the new CTime object to the old one Print(time.__str__()); }
出力結果は以下のとおりです。
FR 0 11:05:16.339 Time testing (XAUUSD,H1) 09:48:10 IN 0 11:05:16.339 Time testing (XAUUSD,H1) 22:48:10
(c) isoformat
この関数は、ISO 8601形式の文字列として時刻を返します。形式は以下のいずれかになります。
- HH:MM:SS.ffffff(マイクロ秒が0でない場合)
- HH:MM:SS(マイクロ秒が0の場合)
- HH:MM:SS.ffffff+HH:MM(UTCオフセットが存在する場合)
- HH:MM:SS+HH:MM(マイクロ秒が0かつUTCオフセットが存在する場合)
string CTime::isoformat(string timespec = "auto") { string hh = StringFormat("%02d", m_hour); string mm = StringFormat("%02d", m_minute); string ss = StringFormat("%02d", m_second); string ms = StringFormat("%03d", m_millisecond); // ----- Timespec switch ----- if(timespec == "hours") return hh; if(timespec == "minutes") return hh + ":" + mm; if(timespec == "seconds") return hh + ":" + mm + ":" + ss; if(timespec == "milliseconds") return hh + ":" + mm + ":" + ss + "." + ms; // ----- AUTO ----- // Python rule: include .mmm only if non-zero if(timespec == "auto") { if(m_millisecond > 0) return hh + ":" + mm + ":" + ss + "." + ms; else return hh + ":" + mm + ":" + ss; } // Invalid timespec -> fallback to full precision return hh + ":" + mm + ":" + ss + "." + ms; }
オプションのtimespec引数により、出力に含める時間要素の精度を指定できます(デフォルトはauto)。次のいずれかになります。
- auto:マイクロ秒が0ならseconds、それ以外はmicroseconds
- hours:時のみ(HH)
- minutes:時と分(HH:MM)
- seconds:時、分、秒(HH:MM:SS)
- milliseconds:ミリ秒まで。秒の小数部はミリ秒に切り捨てられます(HH:MM:SS.sss)
- microseconds:完全な時間(マイクロ秒まで)(HH:MM:SS.ffffff)
使用例
void OnStart() { //--- CTime t(14, 30, 55, &tzinfo, 120); // 14:30:55.120 Print(t.isoformat()); // AUTO -> "14:30:55.120" Print(t.isoformat("hours")); // "14" Print(t.isoformat("minutes")); // "14:30" Print(t.isoformat("seconds")); // "14:30:55" Print(t.isoformat("milliseconds")); // "14:30:55.120" }
(d) strftime
明示的なフォーマット文字列によって制御される、時間を表す文字列を返します。
string CTime::strftime(string format) { string result = ""; for(int i = 0; i < StringLen(format); i++) { if(StringGetCharacter(format, i) == '%' && i + 1 < StringLen(format)) //Start obtaining the values after a % sign { i++; uchar spec = (uchar)StringGetCharacter(format, i); switch(spec) { case 'H': //Find the H for hour result += StringFormat("%02d", m_hour); break; case 'M': //Put minutes in a place of M result += StringFormat("%02d", m_minute); break; case 'S': //put seconds in a place of S result += StringFormat("%02d", m_second); break; default: result += "%"; result += CharToString(spec); break; } } else result += CharToString((char)StringGetCharacter(format, i)); } return result; }
(e) utcoffset
tzinfoがNULLの場合はINT_MAXを返し、それ以外の場合はUTC (GMT)からのオフセット(秒)を返します。
int CTime::tzoffset() { if(m_tzinfo == NULL) return INT_MAX; return m_tzinfo.utcoffset(); }
例
void OnStart() { //--- CTZInfo tzinfo("America/New_York"); CTime time(10, 22, 0, &tzinfo); printf("Tzoffset: %d hours",time.tzoffset()/3600); //we divide by 3600 to get the number of hours }
CTZInfoクラスについては次のセクションで説明します。
出力結果は以下のとおりです。
KK 0 12:39:37.184 Time testing (XAUUSD,H1) Tzoffset: -5 hours
事実として、アメリカ合衆国(ニューヨーク)の時間はGMT-5(UTCより5時間遅れ)です。
(f) dst
tzinfoがNULLに設定されている場合(デフォルト値)、INT_MAXを返します。そうでなければ、サマータイム(DST)を返します。
int CTime::dst(void) { if(m_tzinfo == NULL) return INT_MAX; return m_tzinfo.dst(); }
タイムゾーン情報クラス(tzinfo)
MQL5では、異なるタイムゾーンの情報にアクセスする組み込みの方法がありません。これにより、プログラムが世界中の異なる時間に対応して正確に動作することが難しくなります。
Pythonでは、tzinfoという組み込みクラスがあり、世界中のすべての地域の時間にアクセスすることが可能です。
Python公式ドキュメントによると
class datetime.tzinfo
これは抽象基底クラスであり、直接インスタンス化することはできません。特定のタイムゾーンの情報を扱うために、tzinfoをサブクラス化して定義する必要があります。
tzinfoの具体的なサブクラスのインスタンスは、datetimeやtimeオブジェクトのコンストラクタに渡すことができます。これらのオブジェクトは自分の属性をローカル時間として扱い、tzinfoオブジェクトは渡された日時オブジェクトに対して、UTCからのオフセット、タイムゾーン名、DSTオフセットを返すメソッドをサポートします。
tzinfoの具体的なサブクラスを作成する場合、使用するdatetimeオブジェクトに応じて、標準のtzinfoメソッドを少なくとも実装する必要があります。datetimeモジュールには簡易的な具体的なタイムゾーンサブクラスがあり、UTCや北米のESTやEDTなど、固定オフセットのタイムゾーンを表現できます。
tzinfoの具体的なサブクラスは、必要に応じて以下のメソッドを実装することが求められます。どのメソッドを実装するかは、aware datetimeオブジェクトの利用方法に依存します。迷った場合は、すべてのメソッドを実装しておくと安全です。
Pythonのクラスと同様に、MQL5で実装したCTZInfoクラスは、CDatetimeやCTimeクラスと連携して動作することを目的としており、これらのクラスがタイムゾーン情報を取得する際に役立ちます。
CTZInfoクラスを単独で呼び出すことは可能ですが、現在の時刻などの値に直接アクセスするために使うべきではありません。
このクラス(モジュール)が機能するためには、すべてのタイムゾーン情報を統一したデータベースにまとめておく必要があります。私は https://www.iana.org/time-zonesからすべての情報を抽出し、timezonedb.sqliteという名前のSQLiteデータベースに保存しました。

クラスのコンストラクタ内で、このデータベースを読み込み、後で利用できるように接続を保持します。
#include "sqlite3.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CTZInfo { private: CSqlite3 sqlite; string m_zone_name; int utcoffset(datetime utc_time); public: CTZInfo(const string zone_name); ~CTZInfo(void); }; //+------------------------------------------------------------------+ //| Constructor - open timezone database | //+------------------------------------------------------------------+ CTZInfo::CTZInfo(const string zone_name): m_zone_name(zone_name) { string db_name = "timezonedb.sqlite"; if(!sqlite.connect(db_name, true)) { Print("Failed to open timezone DB"); return; } }
以下は、Pythonでの実装を参考にしつつ、MQL5で実装したクラスで提供されている主なメソッドのいくつかです。若干の変更があります。
(a) utcoffset
ローカル時間がUTCからどれだけずれているかを秒単位で返します。ローカル時間がUTCより西にある場合は負の値、それ以外は正の値になります。
int CTZInfo::utcoffset() { string query = "SELECT gmt_offset FROM time_zone " "WHERE zone_name='" + m_zone_name + "' AND time_start <= " + (string)(int)TimeGMT() + " " "ORDER BY time_start DESC LIMIT 1;"; vector row = sqlite.execute(query).fetchone(); if(row.Size() == 0) return 0; return (int)row[0]; // seconds offset }
例
void OnStart() { //--- CTZInfo tzinfo("America/New_York"); printf("Utc offset: %d hours",tzinfo.utcoffset()/3600); }
出力
2025.11.19 17:32:08.699 Time testing (XAUUSD,H1) Utc offset: -5 hours
(b) dst
夏時間(DST)の調整値をtimedeltaオブジェクトとして返します。DST情報が見つからない場合はNone(または0)を返します。
int CTZInfo::dst() { string query = "SELECT dst FROM time_zone\n" "WHERE zone_name = '" + m_zone_name + "' " "AND time_start <= " + (string)(int)TimeGMT() + " " "ORDER BY time_start DESC\n" "LIMIT 1;"; //--- vector row = sqlite.execute(query).fetchone(); if(row.Size() == 0) // no result return 0; return (int)row[0]; }
(c) fromutc
UTCの日時を受け取り、その時点におけるタイムゾーンのオフセットを適用したローカル日時を返します。
datetime CTZInfo::fromutc(datetime utc_time) { int offset = utcoffset(utc_time); return (datetime)((int)utc_time + offset); }
例
void OnStart() { //--- CTZInfo tzinfo("America/New_York"); Print("From utc: ",tzinfo.fromutc(TimeGMT())); //converts utc time into New york's local time }
出力結果は以下のとおりです。
2025.11.19 17:26:24.400 Time testing (XAUUSD,H1) From utc: 2025.11.19 09:26:24
timedeltaクラス
Python ではtimedeltaオブジェクトは期間を表し、2つのdatetimeまたはdateインスタンスの差や和を表現します。
class datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
すべての引数は省略可能でデフォルトは0です。引数は整数または浮動小数点数で、正または負の値を指定できます。
内部的には、days、seconds、microsecondsのみが保存されます。他の引数は次のように変換されます。
- ミリ秒は1000マイクロ秒に変換される
- 分は60秒に変換される
- 時間は3600秒に変換される
- 週は7日に変換される
その後、days、seconds、microsecondsは正規化され、表現が一意になるように調整されます。条件は次の通りです。
- 0 <= microseconds < 1000000
- 0 <= seconds < 3600*24(1日の秒数)
- -999999999 <= days <= 999999999
MQL5でのtimedeltaモジュールの対応クラスはCTimedeltaであり、Python版に近い機能を持ちますが、若干の変更があります。
関数引数にミリ秒やマイクロ秒は含まれません。これは、datetime変数内でこれらの単位を追跡できないためです。
class CTimedelta { public: CTimedelta(void) {}; ~CTimedelta(void) {}; //+------------------------------------------------------------------+ //| | //| For crafting the desired time given the number of days, hours | //| minutes, seconds, and weeks | //| | //+------------------------------------------------------------------+ template <typename T> static T timedelta(uint days = 0, uint hours = 0, uint minutes = 0, uint seconds = 0, uint weeks = 0) { uint delta_seconds = ((days+(weeks*7)) * 86400) + (hours * 3600) + (minutes * 60) + seconds; return delta_seconds; } template <typename T> static T days(uint days_) { return timedelta<T>(days_); } template <typename T> static T hours(uint hours_) { return timedelta<T>(0, hours_); } template <typename T> static T minutes(uint minutes_) { return timedelta<T>(0, 0, minutes_); } template <typename T> static T seconds(uint seconds_) { return timedelta<T>(0, 0, 0, seconds_); } template <typename T> static T weeks(uint weeks_) { return timedelta<T>(0, 0, 0, 0, weeks_); } };
このクラスは、日、時間、分、秒、週の単位で任意の期間を作成し、秒単位で扱えるように設計されています。また、Pythonと同様に汎用性を持たせるため、テンプレート型を用いて、long、int、ulong、double、またはdatetime型で結果を返すことができます。
使用例
#include <PyMQL5\datetime.mqh> //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- Print("10 minutes datetime: ",CTimedelta::minutes<datetime>(10)); Print("10 minutes seconds: ",CTimedelta::minutes<int>(10)); datetime now = TimeLocal(); printf("Current time: %s 10 minutes ahead: %s",(string)now, string(now + CTimedelta::minutes<datetime>(10))); printf("Current time: %s 1 week, 2 days, 10 hours, and 5 minutes ahead: %s",string(now), string(now + CTimedelta::timedelta<datetime>(2,10,5,0,1))); }
出力結果は以下のとおりです。
CI 0 17:39:37.748 Time testing (XAUUSD,H1) 10 minutes datetime: 1970.01.01 00:10:00 CL 0 17:39:37.748 Time testing (XAUUSD,H1) 10 minutes seconds: 600 HL 0 17:39:37.748 Time testing (XAUUSD,H1) Current time: 2025.11.20 17:39:37 10 minutes ahead: 2025.11.20 17:49:37 HI 0 17:39:37.748 Time testing (XAUUSD,H1) Current time: 2025.11.20 17:39:37 1 week, 2 days, 10 hours, and 5 minutes ahead: 2025.11.30 03:44:37
このシンプルなクラスは、MQL5での日時の加算や減算の操作を簡単にする上で重要です。ネイティブのMQL5では、このような時間演算は少し複雑になりがちだからです。
日付クラスオブジェクト
日付オブジェクトは、理想化された暦上の日付(年、月、日)を表します。現在のグレゴリオ暦が両方向に無限に延長されたものと考えてください。このクラスは、カスタムの「日付」変数(オブジェクト)として扱えます。
Pythonのdatetimeから、dateという関数は、指定された日時に関する日付の情報をすべて含むオブジェクトを返します。
まずは今日の日付を返す方法から始めます。
CDate CDate::today() { m_datetime = TimeLocal(); return CDate(); } 例
#include <PyMQL5\datetime.mqh> void OnStart() { //--- CDate date; Print("Today's date: ",date.today().__str__()); }
出力結果は以下のとおりです。
2025.11.20 18:14:46.217 Time testing (XAUUSD,H1) Today's date: 2025-11-20
以下は、CDateクラス内のすべての必要な関数を含む表です。
| 関数 | 説明 |
|---|---|
CDate::CDate(uint year, uint month, uint day) { if(year < MINYEAR || year > MAXYEAR) Print("ValueError: year out of range"); if(month < 1 || month > 12) Print("ValueError: month out of range"); if(day < 1 || (int)day > DaysInMonth(year, month)) Print("ValueError: day out of range"); m_year = year; m_month = month; m_day = day; } | 年、月、日を受け取り、カスタム日付を作成するコンストラクタ |
CDate(void); | デフォルトコンストラクタ。呼び出すと今日の日付をクラスに設定します。 |
CDate::CDate(const datetime time) { MqlDateTime t; TimeToStruct(time, t); m_year = t.year; m_month = t.mon; m_day = t.day; } | datetime変数から日付情報を抽出してカスタム日付を作成します(例: 18.10.2025 00:00) |
CDate fromtimestamp(datetime ts); | UNIX時間を対応するローカル日付に変換します。 |
CDate CDate::fromisoformat(string s) | 有効なISO 8601形式の文字列から日付を返します。Python datetimeモジュールにある関数とは異なり、MQL5版では現在、次の2種類の形式をサポートしています。
|
CDate fromordinal(int ordinal); | 順序付き日付をCDateオブジェクトに変換します。 |
const int weekday(); | 曜日を整数で返します。月曜が0、日曜が6。MqlDateTime.dayと同様です。 |
const int isoweekday(); | ISO形式の曜日を整数で返します。月曜が1、日曜が7です。 |
static int DaysInMonth(int year, int month); | 指定された月の日数を返します。 |
static bool IsLeapYear(int year); | 指定された年が閏年である場合はtrue、そうでない場合はfalseを返します。 |
CDate replace(int year=-1, int month=-1, int day=-1) const | 指定した日付オブジェクトの値を新しい値に置き換えます。 |
使用例
void OnStart() { //--- CDate date = py_datetime.date(D'29.02.2024'); Print("date: ", date.isoformat()); Print("Weekday: ", date.weekday()); Print("ISO Weekday: ", date.isoweekday()); Print("Ordinal: ", date.toordinal()); Print("Leap year 2024? ", date.IsLeapYear(2024)); Print("__str__: ",date.__str__()); CDate d2 = py_datetime.date().today(); Print("Today: ", d2.isoformat()); Print("From ISO: ", d2.isoformat()); d2 = d2.replace(-1, -1, 30); Print("Replaced: ", d2.isoformat()); //--- from timestamps CDate date3 = date.fromtimestamp(1672531199); Print("Date From timestamps: ",date3.isoformat()); datetime time = py_datetime.fromtimestamp(1672531199); Print("time timestamps: ",time); //--- Print(date_m.fromisoformat("2019-12-04").__str__()); Print(date_m.fromisoformat("20191204").__str__()); //--- CDate today = date.today(); Print(today.ctime()); }
出力結果は以下のとおりです。
OR 0 19:10:29.522 Time testing (XAUUSD,H1) date: 2024-02-29 CD 0 19:10:29.522 Time testing (XAUUSD,H1) Weekday: 3 OQ 0 19:10:29.522 Time testing (XAUUSD,H1) ISO Weekday: 4 CD 0 19:10:29.522 Time testing (XAUUSD,H1) Ordinal: 738945 RD 0 19:10:29.522 Time testing (XAUUSD,H1) Leap year 2024? true HQ 0 19:10:29.522 Time testing (XAUUSD,H1) __str__: 2024-02-29 LJ 0 19:10:29.522 Time testing (XAUUSD,H1) Today: 2025-11-17 LR 0 19:10:29.522 Time testing (XAUUSD,H1) From ISO: 2025-11-17 DD 0 19:10:29.522 Time testing (XAUUSD,H1) Replaced: 2025-11-30 DO 0 19:10:29.522 Time testing (XAUUSD,H1) Date From timestamps: 2023-01-01 EP 0 19:10:29.522 Time testing (XAUUSD,H1) time timestamps: 2023.01.01 02:59:59 QK 0 19:10:29.522 Time testing (XAUUSD,H1) 2019-12-04 OR 0 19:10:29.522 Time testing (XAUUSD,H1) 2019-12-04 CH 0 19:10:29.523 Time testing (XAUUSD,H1) Sun Nov 17 19:10:29 2025
datetimeモジュール
datetimeモジュールは、日付と時間を操作するためのクラスを提供します。このモジュールは、以前のdateおよびtimeモジュールを統合し、さらにいくつかの新しいメソッドを追加しています。
クラスコンストラクタから始めましょう。一部のコンストラクタは既存のdatetime変数を受け取り、その他は特定の日付の年月日と時間を生成するための変数を受け取ります。
class CDatetime { protected: CTZInfo *m_tzinfo; MqlDateTime m_datetime_struct; int weekday(const datetime time); public: CDatetime(); CDatetime(const datetime dt, CTZInfo *tzinfo=NULL); CDatetime(uint year, uint month, uint day, uint hour, uint minutes, uint seconds, CTZInfo *tzinfo=NULL); ~CDatetime(void); //--- custom constructor CDatetime datetime_(uint year, uint month, uint day, uint hour, uint minutes, uint seconds, CTZInfo *tzinfo=NULL); CDatetime combine(CDate &date, CTime &time, CTZInfo *tzinfo=NULL)
combineメソッドはdateオブジェクトとtimeオブジェクトを組み合わせて、datetimeオブジェクトを生成します。
(a) now関数
指定したタイムゾーンに応じて、現在のCDatetimeオブジェクトを返します。
CDatetime CDatetime::now(CTZInfo *tzinfo)
{
return CDatetime(tzinfo.now(), tzinfo);
} 例
#include <PyMQL5\datetime.mqh> CDatetime py_datetime; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- Datetime module testing CTZInfo tzinfo("Africa/Nairobi"); CDatetime now = py_datetime.now(&tzinfo); Print("ctime: ", now.ctime()); }
出力
2025.11.21 20:10:03.116 Time testing (XAUUSD,H1) ctime: Fri Nov 21 20:10:03 2025
(b) fromisoformat
有効なISO 8601形式の文字列からdatetimeオブジェクトを返します。ただし、以下の例外があります。
- タイムゾーンのオフセットには小数秒を含めることができる
- T区切りを任意の単一Unicode文字に置き換えることができる
- 時および分の小数表現はサポートされていない
- 精度を落とした日付(YYYY-MM、YYYY)は現在サポートされていない
- 拡張日付表現(±YYYYYY-MM-DD)は現在サポートされていない
- 順序付き日付(YYYY-OOO)はサポートされていない
CDatetime CDatetime::fromisoformat(string iso) { string orig = iso; //--- Split date & time int sep = StringFind(iso, "T"); if(sep == -1) sep = StringFind(iso, " "); if(sep == -1) { Print("Invalid ISO datetime: ", orig); return CDatetime(); } string date_part = StringSubstr(iso, 0, sep); string time_part = StringSubstr(iso, sep + 1); //--- Parse date YYYY-MM-DD string dparts[]; if(StringSplit(date_part, '-', dparts) != 3) { Print("Invalid ISO date: ", orig); return CDatetime(); } int year = (int)StringToInteger(dparts[0]); int mon = (int)StringToInteger(dparts[1]); int day = (int)StringToInteger(dparts[2]); //--- Extract timezone part string tz = ""; int tz_pos = StringFind(time_part, "+"); if(tz_pos == -1) tz_pos = StringFind(time_part, "-"); if(tz_pos == -1) tz_pos = StringFind(time_part, "Z"); if(tz_pos != -1) { tz = StringSubstr(time_part, tz_pos); time_part = StringSubstr(time_part, 0, tz_pos); } //--- Parse time HH:MM:SS(.fff) int hour=0, minute=0, second=0, millisecond=0; string tparts[]; int n = StringSplit(time_part, ':', tparts); if(n < 2) { Print("Invalid ISO time: ", orig); return CDatetime(); } hour = (int)StringToInteger(tparts[0]); minute = (int)StringToInteger(tparts[1]); if(n >= 3) { int dot = StringFind(tparts[2], "."); if(dot != -1) { second = (int)StringToInteger(StringSubstr(tparts[2], 0, dot)); string frac = StringSubstr(tparts[2], dot + 1); millisecond = (int)(StringToInteger(frac) / MathPow(10, StringLen(frac) - 3)); } else { second = (int)StringToInteger(tparts[2]); } } //--- Timezone if provided CTZInfo *tzinfo = NULL; if(tz == "Z") tzinfo = new CTZInfo("UTC"); else if(StringLen(tz) > 0) { string id = "UTC" + tz; // Example: "UTC+03:00" tzinfo = new CTZInfo(id); } return CDatetime(year, mon, day, hour, minute, second, tzinfo); }
CDateとCTimeに同様の名前の関数がありますが、この関数はそれをさらに進化させ、単一のフォーマットされた文字列で日付と時刻の両方を考慮します。
例
CDatetime time = py_datetime.fromisoformat("2011-11-04T00:05:23Z"); Print("datetime: ",time.__str__());
出力結果は以下のとおりです。
2025.11.22 12:47:18.047 Time testing (XAUUSD,H1) datetime: 2011.11.04 00:05:23
(c) isoformat
CDatetimeオブジェクトに格納されているdatetime情報を、ISO 8601形式の文字列に変換します。
string CDatetime::isoformat(string sep="T", string timespec="auto") { datetime dt = this.__datetime__(); MqlDateTime s; TimeToStruct(dt, s); string hh = StringFormat("%02d", s.hour); string mm = StringFormat("%02d", s.min); string ss = StringFormat("%02d", s.sec); string time_str; if(timespec == "hours") time_str = hh; else if(timespec == "minutes") time_str = hh + ":" + mm; else if(timespec == "seconds") time_str = hh + ":" + mm + ":" + ss; else if(timespec == "milliseconds") time_str = hh + ":" + mm + ":" + ss; else if(timespec == "auto") time_str = hh + ":" + mm + ":" + ss; else time_str = hh + ":" + mm + ":" + ss; string tz = _tz_offset_str(); return StringFormat("%04d-%02d-%02d", s.year, s.mon, s.day) + sep + time_str + tz; }
使用例
CDatetime time = py_datetime.fromisoformat("2011-11-04T00:05:23Z"); Print("Iso format: ", time.isoformat());
出力結果は以下のとおりです。
2025.11.22 12:47:18.047 Time testing (XAUUSD,H1) Iso format: 2011-11-04T00:05:23
(d) strftime
クラスに格納されている日時を、任意の文字列形式にフォーマットします。 通常は表示用に使用されます。
例
CDatetime now = py_datetime.now(&tzinfo); string formatted_time = now.strftime("%Y/%M/%d %H:%M:%S"); Print("formatted time: ", formatted_time);
出力結果は以下のとおりです。
2025.11.22 19:55:55.680 Time testing (XAUUSD,H1) formatted time: 2025/55/22 19:55:55
(e) strptime
strftimeの逆操作をおこないます。ISO 8601形式の文字列から、フォーマットされた時刻情報を解析し、CDatetimeクラス内に格納されるdatetimeオブジェクトに変換します。
例
CDatetime now = py_datetime.now(&tzinfo); string format = "%Y/%M/%d %H:%M:%S"; string formatted_time = now.strftime(format); Print("formatted time: ", formatted_time); Print("Original time: ", now.strptime(formatted_time, format).__datetime__());
出力結果は以下のとおりです。
OL 0 20:00:47.220 Time testing (XAUUSD,H1) formatted time: 2025/00/22 20:00:47 FF 0 20:00:47.220 Time testing (XAUUSD,H1) Original time: 2025.11.22 20:00:47
最終的な考察
Pythonモジュールのdate、time、およびカレンダー関連ユーティリティをMQL5で再現することは、単なるコード書き直しの演習ではありません。これは、MQL5エコシステムにおける実際のギャップを埋めるものです。CTimedelta、CTime、CDatetimeといったクラスを実装することで、MetaTrader 5にはネイティブでは存在しない表現力の高い高度な時間操作ツールを利用できるようになります。
これらの追加により、信頼性の高いタイムスタンプ変換、タイムゾーンの正しい処理、より洗練されたバックテストや時間駆動型システムの構築が可能になります。
本連載でで紹介したすべてのコードを含むリポジトリはhttps://github.com/MegaJoctan/PyMQL5にあります。貢献やバグ修正も歓迎です。
ご一読、誠にありがとうございました。
添付ファイルの表
| ファイル名 | 説明と使用法 |
|---|---|
| Include\errordescription.mqh | MetaTrader 5およびMQL5で生成されるエラーコードを人間が読める形式に変換する関数を含む |
| Include\PyMQL5\datetime.mqh | 日付と時刻を扱うCDateおよびCDatetimeクラスを含む |
| Include\PyMQL5\SQLite3.mqh | Pythonのsqlite3に類似したモジュールで、MetaTrader 5でSQLiteデータベースを読み取る関数を提供する |
| Include\time.mqh | 時間操作用のCTimeクラスを含む |
| Include\TZInfo.mqh | 統一タイムゾーンデータベースからタイムゾーン情報を読み取るCTZInfoクラスを含む |
| Common\Files\timezonedb.sqlite | すべてのタイムゾーン情報(UTCオフセット、タイムゾーン名など)を含むSQLite3データベース |
| Scripts\Time testing.mq5 | この記事で紹介したすべてのメソッドや関数を試すためのテスト用スクリプト |
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/19035
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
MQL5での取引戦略の自動化(第43回):適応型線形回帰チャネル戦略
古典的な戦略を再構築する(第13回):クロスオーバー戦略を新たな次元へ(その2)
MQL5におけるARIMA予測指標
MQL5入門(第29回):MQL5のAPIとWebRequest関数の習得(III)
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索