MetaTrader 5 Platform build 5326: Improvements and fixes - page 4

 

Found a discrepancy in TimeToString versus TimeToStruct.

In essence, there is a cutoff between normal date values and milliseconds date values, which is at: 3001.01.01 07:59:59.

The function TimeToString obeys this correctly, but the function StimeToStruct cuts off one second early, and throws a _LastError 4010: ERR_INVALID_DATETIME

Additionally, I would expect, if TimeToStruct is raising an error, TimeToString should as well, for consistency.


Code to reproduce:

//+------------------------------------------------------------------+
//|                                                  Playground1.mq5 |
//|                 No copyrights applied, common public shared code |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+



void OnStart()
{
    ResetLastError();
    MqlDateTime dtm[1];

    printf("%s", "***");

    TimeToStruct((datetime)0x0000000793406FFE, dtm[0]);
    printf("_LastError: %i", _LastError);
    ArrayPrint(dtm);
    ResetLastError();

    TimeToStruct((datetime)0x0000000793406FFF, dtm[0]);
    printf("_LastError: %i", _LastError);
    ArrayPrint(dtm);
    ResetLastError();


    TimeToStruct((datetime)NULL, dtm[0]);
    printf("_LastError: %i", _LastError);
    ArrayPrint(dtm);
    ResetLastError();
    
    printf("%s; _LastError: %i", TimeToString((datetime)0x0000000793406FFE, TIME_DATE | TIME_SECONDS), _LastError);
    printf("%s; _LastError: %i", TimeToString((datetime)0x0000000793406FFF, TIME_DATE | TIME_SECONDS), _LastError);
    printf("%s; _LastError: %i", TimeToString((datetime)0x0000000793406FFF + 1, TIME_DATE | TIME_SECONDS), _LastError);
    printf("%s; _LastError: %i", TimeToString((datetime)NULL, TIME_DATE | TIME_SECONDS), _LastError);

}




Result of this script:


EDIT: I just noticed, parameters are being read in reverse on function calls, so the last _LastError print-out is actually from the code-line above. - TimeToString returns actually the correct error code, 4010 == ERR_INVALID_DATETIME.

 
Values range from 1 January, 1970 to 31 December, 3000. https://www.mql5.com/en/docs/basis/types/integer/datetime
 
amrali #:
Values range from 1 January, 1970 to 31 December, 3000. https://www.mql5.com/en/docs/basis/types/integer/datetime

Hi Amrali, 

not sure about that, as milliseconds cutoff is defined as value: 3001.01.01 07:59:59.

And it seems, mql is using system fuctions and they behave exactly to this convention.

At least as far as I could deduct from this converter:

https://www.epochconverter.com/

Epoch Converter
Epoch Converter
  • www.epochconverter.com
Convert Unix Timestamps (and many other date formats) to regular dates.
 
Dominik Egert #:

Found a casting bug:

Reference is documentation:

https://www.mql5.com/en/docs/basis/types/casting

Failing code example:

Compiler log:

There were too strict checks for casting. From the next build, you will be able to cast NULL to simple types.

Thank you

 
Alexey Petrov #:

There were too strict checks for casting. From the next build, you will be able to cast NULL to simple types.

Thank you

Thank you for fixing this.
 
Dominik Egert # which is at: 3001.01.01 07:59:59.  4010: ERR_INVALID_DATETIME
That is an invalid datetime. The maximum is 31 December, 3000. Datetime Type - Integer Types - Data Types - Language Basics - MQL4 Reference
 
William Roeder #:
That is an invalid datetime. The maximum is 31 December, 3000. Datetime Type - Integer Types - Data Types - Language Basics - MQL4 Reference
Yeah, I get that, and I can adapt to the value. But shouldnt then the error be reported also when datetime values are not within the defined range? - So both functions actually dont report the error-state correctly then.
 
Dominik Egert #:
Yeah, I get that, and I can adapt to the value. But shouldnt then the error be reported also when datetime values are not within the defined range? - So both functions actually dont report the error-state correctly then.

There is something to fix for sure.

  datetime dtt  = D'3001.01.01 07:59:58';         // compiler warning : invalid date
  datetime dttx = (datetime)0x0000000793406FFE;   // compiler ok
  printf("%s / %s; ", TimeToString(dtt, TIME_DATE | TIME_SECONDS), TimeToString(dttx, TIME_DATE | TIME_SECONDS));

2025.10.10 12:17:52.569    Script (EURUSD,H1)    3000.01.01 07:59:58 / 3001.01.01 07:59:58; 

 
Alain Verleyen #:

There is something to fix for sure.

2025.10.10 12:17:52.569    Script (EURUSD,H1)    3000.01.01 07:59:58 / 3001.01.01 07:59:58; 

A more comprehensive test on the error reporting:

//+------------------------------------------------------------------+
//|                                                  Playground1.mq5 |
//|                 No copyrights applied, common public shared code |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+



void OnStart()
{
    // Loop to find value reported as "ERR_INVALID_DATETIME"

    ResetLastError();
    datetime dtm = D'30.12.3000 23:00:00';

    printf("Starting date for TimeToString(): %s", TimeToString(dtm));
    printf("_LastError: %i", _LastError);

    ResetLastError();
    string str_out = NULL;
    while(_LastError == ERR_SUCCESS)
    {
        str_out += StringFormat("%s\n", TimeToString(dtm));
        dtm += (_LastError == ERR_SUCCESS);
    }
    printf("Result for TimeToString(): \n_LastError: %i; Last datetime value: %lli; Value before failure: %s\n", _LastError, long(dtm), TimeToString(dtm - 1, TIME_DATE|TIME_MINUTES|TIME_SECONDS));


    ResetLastError();
    dtm = D'30.12.3000 23:00:00';
    printf("Starting date for TimeToStruct(): %s", TimeToString(dtm));
    MqlDateTime dtm_struct = {};
    while(_LastError == ERR_SUCCESS)
    {
        TimeToStruct(dtm, dtm_struct);
        dtm += (_LastError == ERR_SUCCESS);
    }
    printf("Result for TimeToStruct(): \n_LastError: %i; Last datetime value: %lli; Value before failure: %s\n", _LastError, long(dtm), TimeToString(dtm - 1, TIME_DATE|TIME_MINUTES|TIME_SECONDS));



    ResetLastError();
    str_out = TimeToString(dtm - 1, TIME_DATE|TIME_MINUTES|TIME_SECONDS);
    ResetLastError();    
    dtm = StringToTime(str_out);
    printf("Result for StringToTime(%s): \n_LastError: %i; Last datetime value: %lli\n", str_out, _LastError, long(dtm));




    ResetLastError();
    dtm = StringToTime("31.12.3000 23:59:59");
    printf("Result for StringToTime(\"31.12.3000 23:59:59\"): \n_LastError: %i; Last datetime value: %lli", _LastError, long(dtm));
    ResetLastError();    
    printf("LastError: %i; Value before failure: %s\n", _LastError, TimeToString(dtm - 1, TIME_DATE|TIME_MINUTES|TIME_SECONDS));

    ResetLastError();
    dtm = StringToTime("01.01.3001 00:00:00");
    printf("Result for StringToTime(\"01.01.3001 00:00:00\"): \n_LastError: %i; Last datetime value: %lli", _LastError, long(dtm));
    ResetLastError();    
    printf("LastError: %i; Value before failure: %s\n", _LastError, TimeToString(dtm - 1, TIME_DATE|TIME_MINUTES|TIME_SECONDS));

    ResetLastError();
    dtm = StringToTime("01.01.3001 07:59:57");
    printf("Result for StringToTime(\"01.01.3001 07:59:57\"): \n_LastError: %i; Last datetime value: %lli", _LastError, long(dtm));
    ResetLastError();    
    printf("LastError: %i; Value before failure: %s\n", _LastError, TimeToString(dtm - 1, TIME_DATE|TIME_MINUTES|TIME_SECONDS));

    ResetLastError();
    dtm = StringToTime("01.01.3001 07:59:58");
    printf("Result for StringToTime(\"01.01.3001 07:59:58\"): \n_LastError: %i; Last datetime value: %lli", _LastError, long(dtm));
    ResetLastError();    
    printf("LastError: %i; Value before failure: %s\n", _LastError, TimeToString(dtm - 1, TIME_DATE|TIME_MINUTES|TIME_SECONDS));

    ResetLastError();
    dtm = StringToTime("01.01.3001 07:59:59");
    printf("Result for StringToTime(\"01.01.3001 07:59:59\"): \n_LastError: %i; Last datetime value: %lli", _LastError, long(dtm));
    ResetLastError();    
    printf("LastError: %i; Value before failure: %s\n", _LastError, TimeToString(dtm - 1, TIME_DATE|TIME_MINUTES|TIME_SECONDS));

    ResetLastError();    
    dtm = StringToTime("01.01.3001 08:00:00");
    printf("Result for StringToTime(\"01.01.3001 08:00:00\"): \n_LastError: %i; Last datetime value: %lli", _LastError, long(dtm));
    ResetLastError();    
    printf("LastError: %i; Value before failure: %s\n", _LastError, TimeToString(dtm - 1, TIME_DATE|TIME_MINUTES|TIME_SECONDS));


    dtm = D'31.12.3000 23:59:59';
    dtm = D'01.01.3001 00:00:00';
    dtm = D'01.01.3001 07:59:57';
    dtm = D'01.01.3001 07:59:58';
    dtm = D'01.01.3001 07:59:59';
    dtm = D'01.01.3001 08:00:00';
}



Producing following output:


 

I have noticed, most of the time CopyTicks is not initiating download of tick-data, though its hard to reproduce this with code other than:


//+------------------------------------------------------------------+
//|                                                  Playground1.mq5 |
//|                 No copyrights applied, common public shared code |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+



void OnStart()
{
    // Local init
    MqlTick ticks_arr[];

    // Call API function
    ResetLastError();
    const int result = CopyTicks(_Symbol, ticks_arr, COPY_TICKS_ALL, NULL, UINT_MAX);

    // Check call result
    printf("Ticks received: %i; ArraySize: %i; LastError: %i", result, ArraySize(ticks_arr), _LastError);

}