Date and Time
Values of type datetime intended for storing date and/or time usually undergo several types of conversion:
- into lines and back to display data to the user and to read data from external sources
- into special structures MqlDateTime (see below) to work with individual date and time components
- to the number of seconds elapsed since 01/01/1970, which corresponds to the internal representation of datetime and is equivalent to the integer type long
For the last item, use datetime to (long) casting, or vice versa, long To (datetime), but note that the supported date range is from January 1, 1970 (value 0) to December 31, 3000 (32535215999 seconds).
For the first two options, the MQL5 API provides the following functions.
string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES)
Function TimeToString converts a value of type datetime to a string with date and time components, according to the mode parameter in which you can set an arbitrary combination of flags:
- TIME_DATE date in the format "YYYY.MM.DD"
- TIME_MINUTES time in the format "hh:mm", i.e., with hours and minutes
- TIME_SECONDS time in "hh:mm:ss" format, i.e. with hours, minutes and seconds
To output the date and time data in full, you can set mode equal to TIME_DATE | TIME_SECONDS (the TIME_DATE | TIME_MINUTES | TIME_SECONDS option will also work, but is redundant). This is equivalent to casting a value of type datetime to (string).
Usage examples are provided in the ConversionTime.mq5 file.
#define PRT(A) Print(#A, "=", (A))
|
The script will print the following log:
(string)time=2021.01.21 23:00:15
|
datetime StringToTime(string value)
The function StringToTime converts a string containing a date and/or time to a value of type datetime. The string can contain only the date, only the time, or the date and time together.
The following formats are recognized for dates:
- "YYYY.MM.DD"
- "YYYYMMDD"
- "YYYY/MM/DD"
- "YYYY-MM-DD"
- "DD.MM.YYYY"
- "DD/MM/YYYY"
- "DD-MM-YYYY"
The following formats are supported for time:
- "hh:mm"
- "hh:mm:ss"
- "hhmmss"
There must be at least one space between the date and time.
If only time is present in the string, the current date will be substituted in the result. If only the date is present in the string, the time will be set to 00:00:00.
If the supported syntax in the string is broken, the result is the current date.
The function usage examples are given in the script ConversionTime.mq5.
void OnStart()
|
In the log, we will see something like the following (####.##.## is the current date the script was launched):
timeonly=21:01
|
In addition to StringToTime, you can use the cast operator (datetime) to convert strings to dates and times. However, the advantage of the function is that when an incorrect source string is detected, the function sets an internal variable with an error code _LastError (which is also available via the function GetLastError). Depending on which part of the string contains uninterpreted data, the error code could be ERR_WRONG_STRING_DATE (5031), ERR_WRONG_STRING_TIME (5032) or another option from the list related to getting the date and time from the string.
bool TimeToStruct(datetime value, MqlDateTime &struct)
To parse date and time components separately, the MQL5 API provides the TimeToStruct function which converts a value of type datetime into the MqlDateTime structure:
struct MqlDateTime
|
The days of the week are numbered in the American manner: 0 for Sunday, 1 for Monday, and so on up to 6 for Saturday. They can be identified using the built-in ENUM_DAY_OF_WEEK enumeration.
The function returns true if successful and false on error, in particular, if an incorrect date is passed.
Let's check the performance of the function using the ConversionTimeStruct.mq5 script. To do this, let's create the time array of type datetime with test values. We will call TimeToStruct for each of them in a loop.
The results will be added to an array of structures MqlDateTime mdt[]. We will first initialize it with zeros, but since the built-in function ArrayInitialize does not know how to handle structures, we will have to write an overload for it (in the future we will learn an easier way to fill an array with zeros: in the section Zeroing objects and arrays the function ZeroMemory will be introduced).
int ArrayInitialize(MqlDateTime &mdt[], MqlDateTime &init)
|
After the process, we will output the array of structures to the log using the built-in function ArrayPrint. This is the easiest way to provide nice data formatting (it can be used even if there is only one structure: just put it in an array of size 1).
void OnStart()
|
As a result, we get the following strings in the log:
time[i]=2021.01.28 23:00:15
|
You can make sure that all fields have received the appropriate values. For incorrect initial dates, we store the error code in the year field (in this case, there is only one such error: 4010, ERR_INVALID_DATETIME).
Recall that for the maximum date value in MQL5, the DATETIME_MAX constant is introduced, equal to the integer value 0x793406fff, which corresponds to 23:59:59 December 31, 3000.
The most common problem that is solved using the function TimeToStruct, is getting the value of a particular date/time component. Therefore, it makes sense to prepare an auxiliary header file (MQL5Book/DateTime.mqh) with a ready implementation option. The file has the datetime class.
class DateTime
|
The class comes with several macros that make it easier to call its methods.
#define TimeDayOfWeek(T) DateTime::assign(T).timeDayOfWeek()
|
The class has the mdtstruct field of the MqlDateTime structure type. This field is used in all internal conversions. Structure fields are read using getter methods: a corresponding method is allocated for each field.
One static instance is defined inside the class: _DateTime (one object is enough, because all MQL programs are single-threaded). The constructor is private, so trying to create other datetime objects will fail.
Using macros, we can conveniently receive separate components from datetime, for example, the year (TimeYear(T)), month (TimeMonth(T)), number (TimeDay(T)), or day of the week (TimeDayOfWeek(T)).
If from one value of datetime it is necessary to receive several fields, then it is better to use similar macros in all calls except the first one without a parameter and starting with the underscore symbol: they read the desired field from the structure without re-setting the date/time and calling the TimeToStruct function. For example:
// use the DateTime class from MQL5Book/DateTime.mqh:
|
The following strings should appear in the log.
EnumToString(DateTime::_DateTime.assign(time[0]).__TimeDayOfWeek())=THURSDAY
|
The built-in function EnumToString converts an element of any enumeration into a string. It will be described in a separate section.
datetime StructToTime(MqlDateTime &struct)
The StructToTime function performs a conversion from the MqlDateTime structure (see above the description of the TimeToStruct function) containing date and time components, into a value of type datetime. The fields day_of_week and day_of_year are not used.
If the state of the remaining fields is invalid (corresponding to a non-existent or unsupported date), the function may return either a corrected value, or WRONG_VALUE (-1 in the representation of type long), depending on the problem. Therefore, you should check for an error based on the state of the global variable _LastError. A successful conversion is completed with code 0. Before converting, you should reset a possible failed state in _LastError (preserved as an artifact of the execution of some previous instructions) using the ResetLastError function.
The StructToTime function test is also provided in the script ConversionTimeStruct.mq5. The array of structures parts is converted to datetime in the loop.
MqlDateTime parts[] =
|
For each element, the resulting value and an error code are displayed.
[year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
|
Note that the function corrects some values without raising the error flag. So, in element number 2, we passed the date, February 30, 2021, into the function, which was converted to March 2, 2021, and _LastError = 0.