Внедрение в MQL5 практических модулей из других языков (Часть 04): Модули time, date и datetime из Python
Разделы
- Введение
- Класс time
- Класс Time zone information
- Класс Time delta
- Объект класс date
- Модуль datetime
- Заключение
Введение
Время — основополагающая единица нашей жизни; все, что существует в этой Вселенной, измеряется временем. В повседневной жизни мы оцениваем свои цели и время, необходимое для их достижения, и даже составляем строгие графики для измерения (мониторинга) выполнения задач с помощью устройств для отслеживания времени (например, смартфонов и часов).
Когда речь заходит об алгоритмической торговле и торговле в целом, время по-прежнему остается важнейшим параметром. Мы часто принимаем торговые решения, основанные на временных рамках, и обычно оцениваем свои достижения ежедневно, ежемесячно и еженедельно.
Язык программирования MQL5 обладает множеством встроенных функций для управления и оценки времени, обеспечивая работу наших алгоритмических торговых систем с учетом реального времени. Однако выбранный нами язык программирования предлагает очень простой (базовый) и порой не очень подходящий человеку способ работы со временем, датами и т.п., по сравнению с другими языками наподобие языка Python, предлагающими богатый набор модулей для выполнения задач, таких как datetime, calendar, time, zoneinfo и т. д.

В этой статье мы собираемся реализовать в языке программирования MQL5 модули, аналогичные тем, которые предлагаются в Python для обработки времени.
Класс (модуль) time
Начнем с класса time, который содержит основные функции (методы) для работы со временем в языке программирования Python.
Согласно документации Python:
Объект time представляет собой (локальное) время суток, не привязанное к конкретной дате и подлежащее корректировке с помощью объекта tzinfo.
class datetime.time(hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0)
Все аргументы являются необязательными. tzinfo может быть None или экземпляром подкласса tzinfo. Остальные аргументы должны быть целыми числами в следующих диапазонах:
- 0 <= час < 24,
- 0 <= минута < 60,
- 0 <= секунда < 60,
- 0 <= микросекунда < 1000000
Если аргумент выходит за пределы указанных диапазонов, генерируется исключение ValueError. Все значения по умолчанию равны 0, за исключением tzinfo, для которого значение по умолчанию равно None.
Python предлагает такие классы, как datetime и date с использованием аналогичных методов для работы со временем. Однако класс, названный time, из модуля с именем time отвечает только за работу со временем (без учета даты). Точно так же, как вам хотелось бы узнать конкретное время суток.
Внутри класса с именем CTime нам необходимо проверить значения, чтобы убедиться, что пользователь указал соответствующие значения для создания объекта time в конструкторе класса, аналогично тому, как это делается на языке 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 хранит информацию о конкретном часовом поясе, к которому относится объект time.
Ниже приведены несколько методов, присутствующих в классе CTime.
(a) fromisoformat
Эта функция возвращает объект CTime, соответствующий переменной time_string в любом допустимом формате ISO 8601, за исключением следующих случаев:
- Смещение часовых поясов может составлять доли секунды.
- Начальная буква Т, обычно необходимая в тех случаях, когда может возникнуть неоднозначность между датой и временем, в данном случае не требуется.
- Дробные части секунды могут содержать любое количество цифр (все цифры после 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, в форматы string и 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 можно указать для создания относительного (naive) объекта времени из объекта абсолютного (aware) времени без преобразования данных о времени.
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[:SS[.ffffff]], если utcoffset() не возвращает None
- HH:MM:SS+HH:MM[:SS[.ffffff]], если количество микросекунд равно 0, а utcoffset() не возвращает None
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: такое же значение, как у seconds, если значение microseconds равно 0, в противном случае — то же значение, что и у 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) явно заданного формата.
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 (на 5 часов отстает от UTC).
(f) dst
Возвращает INT_MAX, если значение tzinfo установлено на NULL (значение по умолчанию); в противном случае возвращает значение летнего времени.
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, название часового пояса и смещение летнего времени, и все эти характеристики — относительно объекта date или time, переданного в них.
Вам необходимо создать конкретный подкласс и (как минимум) предоставить реализации стандартных методов tzinfo, необходимых для используемых вами методов datetime. Модуль datetime предоставляет time zone — простой конкретный подкласс класса tzinfo, который может представлять часовые зоны с фиксированным смещением относительно UTC, такие как само время UTC или североамериканские EST и EDT.
Конкретному подклассу tzinfo может потребоваться реализация следующих методов. Какие именно методы нужны, зависит от того, для каких целей используются известные объекты datetime. В случае сомнений просто реализуйте все методы.
Подобно классу в языке программирования Python, реализованный в MQL5 класс с именем CTZInfo предназначен для гармоничной работы с классами CDatetime и CTime, помогая этим двум классам получать информацию о часовых поясах.
Несмотря на то, что вы можете вызывать этот класс вне других классов, работающих с временными переменными, вам не следует использовать его для доступа к его значениям, таким как current time (текущее время), и т. д.
Для работы этого класса (модуля) нам необходима единая база данных со всей информацией о часовых поясах. Мне пришлось извлечь всю информацию из https://www.iana.org/time-zones и сохранить эти сведения в базе данных SQLite с именем timezonedb.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; } }
Ниже приведены некоторые методы, предоставляемые классом, реализованным на языке MQL5, примерно как в языке Python, с небольшими изменениями.
(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 или None, если информация о летнем времени не найдена.
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 и возвращает локализованные дату и время (сдвиг 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 представляет собой длительность, разницу или сумму двух значений экземпляров datetime или date.
class datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
Все аргументы являются необязательными и по умолчанию равны 0. Аргументы могут быть целыми числами или дробными числами с плавающей запятой, а также могут быть положительными или отрицательными.
Внутри системы хранятся только дни, секунды и микросекунды. Аргументы преобразуются в следующие единицы:
- Миллисекунда преобразуется в 1000 микросекунд.
- Минута преобразуется в 60 секунд.
- Час преобразуется в 3600 секунд.
- Неделя преобразуется в 7 дней.
А затем дни, секунды и микросекунды нормализуются таким образом, чтобы представление было уникальным, причем
- 0 <= микросекунды < 1000000
- 0 <= секунд < 3600*24 (количество секунд в сутках)
- -999999999 <= дни <= 999999999
Ниже приведён эквивалент модуля timedelta из языка Python в формате языка MQL5 с небольшими изменениями.
В аргументах функции отсутствуют миллисекунды и микросекунды, поскольку эти два параметра невозможно сохранить (отследить) в переменной 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, мы используем имя (имена) типа (typename), чтобы гарантировать возможность возврата времени, созданного в секундах, с использованием переменных типа 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.
Объект класса date
Объект date представляет собой дату (год, месяц и день) в идеализированном календаре, при этом текущий григорианский календарь бесконечно расширен в обоих направлениях. Рассматривайте этот класс как пользовательскую переменную (объект) типа date.
В языке Python функция с именем 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) | Возвращает дату, соответствующую заданной строке date_string в любом допустимом формате ISO 8601. В отличие от функции, присутствующей в модуле (модулях) Python с именем datetime, наша функция в MQL5 в настоящее время поддерживает только два формата ISO, используя эти формулы.
|
CDate fromordinal(int ordinal); | Преобразует порядковую дату в объект CDate. |
const int weekday(); | Возвращает день недели в виде целого числа, где понедельник равен 0, а воскресенье — 6, аналогично функции MqlDateTime.day. |
const int isoweekday(); | Возвращает день недели в виде целого числа, где понедельник равен 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 | Заменяет одно или несколько значений заданного объекта date новыми значениями. |
Пример использования:
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
Возвращает объект datetime, соответствующий объекту date_string в любом допустимом формате ISO 8601, за исключением следующих случаев.
- Смещение часовых поясов может составлять доли секунды.
- Разделитель T можно заменить любым символом Unicode.
- Дробные части часов и минут не поддерживаются.
- В настоящее время даты с пониженной точностью (ГГГГ-ММ, ГГГГ) не поддерживаются.
- Расширенные представления дат в настоящее время не поддерживаются (±ГГГГГ-ММ-ДД).
- В настоящее время порядковые даты не поддерживаются (ГГГГ-ППП).
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
Преобразует информацию datetime, хранящуюся в объекте CDatetime, в строковый формат времени в соответствии со стандартом 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
Преобразует сохраненные данные datetime в классе в желаемый строковый формат, обычно для демонстрационных целей.
Пример ниже.
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 в объект datetime, хранящийся в классе CDatetime.
Пример ниже.
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 на языке 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 | Модуль похож на sqlite3 в Python, содержащий функции для чтения баз данных SQLITE в MetaTrader 5. |
| Include\time.mqh | Содержит класс CTime для работы со временем. |
| Include\TZInfo.mqh | В ней есть класс CTZInfo для чтения информации о часовых поясах из универсальной базы данных time. |
| Common\Files\timezonedb.sqlite | База данных SQLite3, содержащая информацию обо всех часовых поясах, включая смещение UTC, названия часовых поясов и т. д. |
| Scripts\Time testing.mq5 | Площадка для тестирования всех методов и функций, рассмотренных в этой статье. |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/19035
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Статистический арбитраж на основе коинтегрированных акций (Часть 1): Tесты Энгла — Грейнджера и Йохансена на коинтеграцию
Торговые инструменты на MQL5 (Часть 15): Эффекты размытия canvas, рендеринг теней и плавная прокрутка колесом мыши
Нейросети в трейдинге: Многодоменная архитектура анализа финансовых данных (Окончание)
Эволюционный отбор LLM-агентов в MetaTrader 5
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования