Fecha y hora
Los valores del tipo datetime destinados a almacenar fecha y/o hora suelen sufrir varios tipos de conversión:
- en líneas y viceversa para mostrar datos al usuario y leer datos de fuentes externas;
- en estructuras MqlDateTime especiales (véase más abajo) para trabajar con componentes individuales de fecha y hora;
- al número de segundos transcurridos desde el 01/01/1970, que corresponde a la representación interna de datetime y equivale al tipo entero. long
Para el último elemento, utilice la conversión de datetime a (long), o viceversa, long a (datetime), pero tenga en cuenta que el intervalo de fechas admitido va del 1 de enero de 1970 (valor 0) al 31 de diciembre de 3000 (32535215999 segundos).
Para las dos primeras opciones, la API de MQL5 proporciona las siguientes funciones:
string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES)
La función TimeToString convierte un valor de tipo datetime en una cadena con componentes de fecha y hora, de acuerdo con el parámetro mode en el que se puede establecer una combinación arbitraria de banderas:
- TIME_DATE - fecha en el formato «AAAA.MM.DD».
- TIME_MINUTES - hora en el formato «hh:mm», es decir, con horas y minutos
- TIME_SECONDS - hora en formato «hh:mm:ss», es decir, con horas, minutos y segundos
Para obtener los datos completos de fecha y hora, puede configurar mode como TIME_DATE | TIME_SECONDS (la opción TIME_DATE | TIME_MINUTES | TIME_SECONDS también funciona, pero es redundante). Esto equivale a pasar un valor de tipo datetime a (string).
En el archivo ConversionTime.mq5 se ofrecen ejemplos de uso.
#define PRT(A) Print(#A, "=", (A))
|
El script imprimirá el siguiente registro:
(string)time=2021.01.21 23:00:15
|
datetime StringToTime(string value)
La función StringToTime convierte una cadena que contiene una fecha y/o una hora en un valor del tipo datetime. La cadena puede contener sólo la fecha, sólo la hora, o la fecha y la hora juntas.
Se reconocen los siguientes formatos para las fechas:
- «AAAA.MM.DD»
- «AAAAMMDD»
- «AAAA/MM/DD»
- «AAAA-MM-DD»
- «DD.MM.AAAA»
- «DD/MM/AAAA»
- «DD-MM-AAAA»
Se admiten los siguientes formatos para la hora:
- «hh:mm»
- «hh:mm:ss»
- «hhmmss»
Debe haber al menos un espacio entre la fecha y la hora.
Si en la cadena sólo aparece la hora, la fecha actual se sustituirá en el resultado. Si en la cadena sólo está presente la fecha, la hora se fijará en 00:00:00.
Si se rompe la sintaxis admitida en la cadena, el resultado es la fecha actual.
Los ejemplos de uso de las funciones figuran en el script ConversionTime.mq5.
void OnStart()
|
En el registro, veremos algo como lo siguiente (####.##.## es la fecha actual en que se lanzó el script):
timeonly=21:01
|
Además de StringToTime, puede utilizar el operador de conversión (datetime) para convertir cadenas en fechas y horas. Sin embargo, la ventaja de la función es que cuando se detecta una cadena fuente incorrecta, la función establece una variable interna con un código de error _LastError (que también está disponible a través de la función GetLastError). Dependiendo de qué parte de la cadena contenga datos no interpretados, el código de error podría ser ERR_WRONG_STRING_DATE (5031), ERR_WRONG_STRING_TIME (5032) u otra opción de la lista relacionada con la obtención de la fecha y la hora a partir de la cadena.
bool TimeToStruct(datetime value, MqlDateTime &struct)
Para analizar sintácticamente los componentes de fecha y hora por separado, la API de MQL5 proporciona la función TimeToStruct, que convierte un valor de tipo datetime en la estructura MqlDateTime:
struct MqlDateTime
|
Los días de la semana están numerados a la manera americana: 0 para el domingo, 1 para el lunes, y así sucesivamente hasta 6 para el sábado. Pueden identificarse utilizando la enumeración integrada ENUM_DAY_OF_WEEK.
La función devuelve true si tiene éxito y false en caso de error, en particular si se pasa una fecha incorrecta.
Comprobemos el rendimiento de la función utilizando el script ConversionTimeStruct.mq5. Para ello, vamos a crear el array time de tipo datetime con valores de prueba. Llamaremos a TimeToStruct para cada uno de ellos en un bucle.
Los resultados se añadirán a un array de estructuras MqlDateTime mdt[]. Primero lo inicializaremos con ceros, pero como la función integrada ArrayInitialize no sabe manejar estructuras, tendremos que escribir una sobrecarga para ella (más adelante descubriremos una forma más fácil de rellenar un array con ceros: en la sección Puesta a cero de objetos y arrays se introducirá la función ZeroMemory).
int ArrayInitialize(MqlDateTime &mdt[], MqlDateTime &init)
|
Tras el proceso, enviaremos el array de estructuras al registro utilizando la función integrada ArrayPrint. Esta es la forma más fácil de proporcionar un formato de datos agradable (se puede utilizar incluso si sólo hay una estructura: basta con ponerla en un array de tamaño 1).
void OnStart()
|
Como resultado, obtenemos las siguientes cadenas en el registro:
time[i]=2021.01.28 23:00:15
|
Puede asegurarse de que todos los campos han recibido los valores adecuados. Para las fechas iniciales incorrectas, almacenamos el código de error en el campo year(en este caso, sólo hay un error de este tipo: 4010, ERR_INVALID_DATETIME).
Recordemos que para el valor máximo de fecha en MQL5 se introduce la constante DATETIME_MAX, igual al valor entero 0x793406fff, que corresponde a las 23:59:59 horas del 31 de diciembre de 3000.
El problema más común que se resuelve utilizando la función TimeToStruct es obtener el valor de un determinado componente fecha/hora. Por lo tanto, tiene sentido preparar un archivo de encabezado auxiliar (MQL5Book/DateTime.mqh) con una opción de implementación lista. El archivo tiene la clase datetime.
class DateTime
|
La clase viene con varias macros que facilitan la llamada a sus métodos.
#define TimeDayOfWeek(T) DateTime::assign(T).timeDayOfWeek()
|
La clase tiene el campo mdtstruct del tipo de estructura MqlDateTime. Este campo se utiliza en todas las conversiones internas. Los campos de estructura se leen mediante métodos getter: a cada campo se le asigna un método correspondiente.
Se define una instancia estática dentro de la clase: _DateTime (un objeto es suficiente, porque todos los programas MQL son de un solo hilo). El constructor es privado, por lo que intentar crear otros objetos datetime fallará.
Utilizando macros podemos recibir cómodamente componentes separados de datetime, como por ejemplo el año (TimeYear(T)), el mes (TimeMonth(T)), el número (TimeDay(T)), o el día de la semana (TimeDayOfWeek(T)).
Si a partir de un valor de datetime es necesario recibir varios campos, entonces es mejor utilizar macros similares en todas las llamadas excepto en la primera sin parámetro y empezando por el símbolo de subrayado: leen el campo deseado de la estructura sin reajustar la fecha/hora y llamar a la función TimeToStruct. Por ejemplo:
// use the DateTime class from MQL5Book/DateTime.mqh:
|
En el registro deberían aparecer las siguientes cadenas.
EnumToString(DateTime::_DateTime.assign(time[0]).__TimeDayOfWeek())=THURSDAY
|
La función integrada EnumToString convierte un elemento de cualquier enumeración en una cadena. Se describirá en una sección aparte.
datetime StructToTime(MqlDateTime &struct)
La función StructToTime realiza una conversión de la estructura MqlDateTime (véase más arriba la descripción de la función TimeToStruct), que contiene componentes de fecha y hora, en un valor de tipo datetime. Los campos day_of_week y day_of_year no se utilizan.
Si el estado de los campos restantes no es válido (correspondiente a una fecha inexistente o no admitida), la función puede devolver un valor corregido, o WRONG_VALUE (-1 en la representación de tipo long), dependiendo del problema. Por lo tanto, debe comprobar si se produce un error según el estado de la variable global _LastError. Una conversión correcta se completa con el código 0. Antes de convertir, debe restablecer un posible estado fallido en _LastError (conservado como artefacto de la ejecución de algunas instrucciones anteriores) utilizando la función ResetLastError.
La prueba de la función StructToTime también se proporciona en el script ConversionTimeStruct.mq5. El array de estructuras parts se convierte en datetime en el bucle.
MqlDateTime parts[] =
|
Para cada elemento se muestra el valor resultante y un código de error.
[year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
|
Observe que la función corrige algunos valores sin levantar la bandera de error. Así, en el elemento número 2, pasamos la fecha, 30 de febrero de 2021, a la función, que fue convertida a 2 de marzo de 2021, y _LastError = 0.