Trying to make datetime check for Daylight Savings more more efficient, any ideas?

 
#property strict
#property script_show_inputs

extern datetime TimeNowTest = D'2015.01.10';

datetime DayLightShifts[9] = {D'2014.11.02 02:00', //0
                              D'2015.03.08 02:00', //1
                              D'2015.11.01 02:00', //0
                              D'2016.03.13 02:00', //1
                              D'2016.11.06 02:00', //0
                              D'2017.03.12 02:00', //1
                              D'2017.11.05 02:00', //0
                              D'2018.03.11 02:00', //1
                              D'2018.11.04 02:00'}; //0

void OnStart(){

   int GMTOffset_ = -1;
   
   int arraySize = ArraySize(DayLightShifts);
   for(int i = 0; i < arraySize; i++){
      if(TimeNowTest >= DayLightShifts[i] && TimeNowTest < DayLightShifts[i+1]){
         GMTOffset_ = (int)MathMod(i, 2);
         break;
      }
   }

   Print("GMTOffset: ", GMTOffset_);

}

This is my test script, I'm looking to backtest on GMT+0 historical data and to run it per minute in an EA, replacing the extern TimeNowTest with Time[0].

It returns 0 or 1 depending on the TimeNowTest/Time[0].

Any ideas on how this could be more efficient?

 
Raiden:

This is my test script, I'm looking to backtest on GMT+0 historical data and to run it per minute in an EA, replacing the extern TimeNowTest with Time[0].

It returns 0 or 1 depending on the TimeNowTest/Time[0].

Any ideas on how this could be more efficient?

Use a formula for each city dst


datetime CheckDSTStartUS(int cityYear)
{
   datetime dstStartUS=0;
   if(cityYear<1987) return(0);
   int DSTstring_start_dom = 0;
      if (cityYear >= 1987 && cityYear <= 2006) 
   {
      dstStartUS=CheckdstDate(0,1,2,4,cityYear);   // first Sunday in April
   }
   else if (cityYear >= 2007) 
   {
      dstStartUS=CheckdstDate(DSTdayStartUS,DSTweekStartUS,DSThourStartUS,DSTmonthStartUS,cityYear);   // second Sunday in March
   } 
   PrintX(5,PrintTagMax,"dstStartUS->",DateStringA(dstStartUS));
   return(dstStartUS);  
}

datetime CheckDSTEndUS(int cityYear)
{
   datetime dstEndUS=0;
   if(cityYear<1987) return(0);
      if (cityYear >= 1987 && cityYear <= 2006) 
   {
       dstEndUS=CheckdstDate(0,5,2,10,cityYear);      // last Sunday in October
   }
   else if (cityYear >= 2007) 
   {
      dstEndUS=CheckdstDate(DSTdayEndUS,DSTweekEndUS,DSThourEndUS,DSTmonthEndUS,cityYear);     // first Sunday in November
   } 
   PrintX(5,PrintTagMax,"dstEndUS->",DateStringA(dstEndUS));
   return(dstEndUS);  
}



datetime CheckdstDate(int dayOfWeekNum, int dayOfWeekCount, double dayHour, int dayMonthNum, int cityYear)
{ 
   int count=0;
   int weekCount=1;
   datetime dstDate=StringToTime(StringConcatenate(IntegerToString(cityYear),".",IntegerToString(dayMonthNum),".","01"));
   datetime lastdstDate;
   while(dstDate<=TimeCurrent()+PERIOD_MN1*12*60)
   {   
      // Print("TimeDayOfWeek(dstDate)->",TimeDayOfWeek(dstDate));
      if(dayOfWeekNum==TimeDayOfWeek(dstDate)) 
      { 
         lastdstDate=dstDate+dayHour*60*60;
         weekCount=weekCount+1;
      }
      if((dayOfWeekNum==TimeDayOfWeek(dstDate) && weekCount>dayOfWeekCount) ||  TimeMonth(dstDate+24*60*60)!=TimeMonth(dstDate))
      { 
         return(lastdstDate);
      }
      dstDate=dstDate+24*60*60; //Print("dstDate->",dstDate);
   }
   Print("ERROR  ","dstDate->",DateStringA(dstDate));
   return(0);
}
 
rod178:

Use a formula for each city dst


Thanks for the suggestion. It's however very costly to use any string to datetime conversion and other time functions. (I'm just using US shift for the moment. Can easily add another array for EUR shift if necessary.)

I've whittled it down to:

#property strict
#property script_show_inputs

extern datetime TimeNowTest = D'2015.01.10';

datetime DayLightShiftDates[36] = {D'2003.04.06 02:00', //1 //NB: 1st date in array must start with 1 for the loop below to work properly (2003.04.06 02:00 to 2003.10.26 02:00 must have GMTOffset = 1)
                                   D'2003.10.26 02:00', //0
                                   D'2004.04.04 02:00', //1
                                   D'2004.10.31 02:00', //0
                                   D'2005.04.03 02:00', //1
                                   D'2005.10.30 02:00', //0
                                   D'2006.04.02 02:00', //1
                                   D'2006.10.29 02:00', //0
                                   D'2007.03.11 02:00', //1
                                   D'2007.11.04 02:00', //0
                                   D'2008.03.09 02:00', //1
                                   D'2008.11.02 02:00', //0
                                   D'2009.03.08 02:00', //1
                                   D'2009.11.01 02:00', //0
                                   D'2010.03.14 02:00', //1
                                   D'2010.11.07 02:00', //0
                                   D'2011.03.13 02:00', //1
                                   D'2011.11.06 02:00', //0
                                   D'2012.03.11 02:00', //1
                                   D'2012.11.04 02:00', //0
                                   D'2013.03.10 02:00', //1
                                   D'2013.11.03 02:00', //0
                                   D'2014.03.09 02:00', //1
                                   D'2014.11.02 02:00', //0
                                   D'2015.03.08 02:00', //1
                                   D'2015.11.01 02:00', //0
                                   D'2016.03.13 02:00', //1
                                   D'2016.11.06 02:00', //0
                                   D'2017.03.12 02:00', //1
                                   D'2017.11.05 02:00', //0
                                   D'2018.03.11 02:00', //1
                                   D'2018.11.04 02:00', //0
                                   D'2019.03.10 02:00', //1
                                   D'2019.11.03 02:00', //0
                                   D'2020.03.08 02:00', //1
                                   D'2020.11.01 02:00'  //0
                                  };

void OnStart(){

   int DSTOffset = 0;
   
   int arraySize = ArraySize(DayLightShiftDates);
   for(int i = 0; i < arraySize; i=i+2){
      if(TimeNowTest >= DayLightShiftDates[i] && TimeNowTest < DayLightShiftDates[i+1]){
         DSTOffset = 1;
         Print(TimeNowTest, " is between ", DayLightShiftDates[i], " and ", DayLightShiftDates[i+1]);
         break;
      }
   }

   Print("DSTOffset: ", DSTOffset);

}

DSTOffset defaults to 0, the loop only checks half of the elements, MathMod() is done away with. (Naturally get rid of the Print() statement in production)

 
Raiden:

Thanks for the suggestion. It's however very costly to use any string to datetime conversion and other time functions. (I'm just using US shift for the moment. Can easily add another array for EUR shift if necessary.)

I've whittled it down to:

DSTOffset defaults to 0, the loop only checks half of the elements, MathMod() is done away with. (Naturally get rid of the Print() statement in production)



if you do no want to continuously perform the calculations, they could be loaded into an array(s) at initialization

ie  US dst 

 Starts second Sunday in March

 Ends  first Sunday in November

 
Raiden:

Any ideas on how this could be more efficient?

Surely it depends on the context you need it for? I haven't checked, but this code will presumably execute in microseconds. I can't imagine that you will see any benefit in real trading from trying to improve its efficiency; there'll only be a point if you need to run it in backtesting/optimisation.

If you are going to be (a) doing the DST check frequently and (b) in backtesting, then the obvious way to increase efficiency is to cache the last date for which the function was called and its result, and to return that value if the time hasn't ticked over into a new day.

 

Machine translation of text carried out by moderator from Spanish to English (code comments were not translated).

I hope these functions help you.

------------------------------------------------------------------------------------------------

Possible alternative code to the pre-set MT4 function TimeDaylightSavings() to determine the summer/winter time change for the New York (DST - EDT) and London (BST) time zones - Daylight Saving Time

Basically, it seeks to detect the second Sunday of March and the first Sunday of November to determine the summer time for New York and the last Sunday of the month of March and the last Sunday of October to determine the summer time for London. Once having the range of dates, the DST and BST functions return the date adjusting one hour earlier than the time of the broker's MT4 terminal client. It is possible to change the return of a date to a boolean validation, according to the needs of your code.

Input: datetime DST(date), BST(date)

Departure: Date modified to -3600 seconds (1 hour) if it is in summer time, or remains the same if it is in winter time. Times in GMT+3 (BrokerTime)

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
//
// FUNCIONES PARA DETERMINAR HORARIO DE VERANO/INVIERNO NEW YORK Y LONDRES
//
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DST: Daylight Saving Time / EDT: Eastern Daylight Time (VERANO) (GMT -4)- Segundo domingo de marzo hasta primer domingo de noviembre
// EST: Eastern Standard Time (INVIERNO) (GMT -5)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

datetime Segundo_Domingo_Marzo(int year)
{
 datetime segundo_domingo = 0;
 //datetime fecha = D'2023.03.01 10:00';
 datetime fecha = StrToTime(IntegerToString(year)+"."+"03"+"."+"01"+" "+"10:00");
 int contador = 0;
 for(int i=0;i<=15;i++)
 {
  datetime fecha_temp = fecha + (i*60*60*24);
  int is_domingo = TimeDayOfWeek(fecha_temp) == 0 ? contador=contador+1:NULL;
  if (contador == 2)
      {
      segundo_domingo = fecha_temp; 
      contador = 0;
      //Print("Segundo Domingo: ",segundo_domingo);
      }
}

return segundo_domingo;
}

datetime Primer_Domingo_Noviembre(int year)
{
 datetime primer_domingo = 0;
 //datetime fecha = D'2023.11.01 10:00';
 datetime fecha = StrToTime(IntegerToString(year)+"."+"11"+"."+"01"+" "+"10:00");
 int contador = 0;
 for(int i=0;i<=8;i++)
 {
  datetime fecha_temp = fecha + (i*60*60*24);
  int is_domingo = TimeDayOfWeek(fecha_temp) == 0 ? contador=contador+1:NULL;
  if (contador == 1)
      {
      primer_domingo = fecha_temp; 
      contador = 0;
      //Print("Primer Domingo: ",primer_domingo);
      }
}

return primer_domingo;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// BST: British Summer Time (VERANO) (GMT +1) - Último domingo de marzo hasta último domingo de octubre
// GMT: GreenWich Mean Time (INVIERNO) (GMT 0 / UTC)
//////////////////////////////////////////////////////////////////////////////////////////////////////////

datetime Ultimo_Domingo_Marzo(int year)
{
 datetime ultimo_domingo = 0;
 //datetime fecha = D'2022.03.01 10:00';
 datetime fecha = StrToTime(IntegerToString(year)+"."+"03"+"."+"01"+" "+"04:00");
 int contador = 0;
 for(int i=0;i<=31;i++)
 {
  datetime fecha_temp = fecha + (i*60*60*24);
  int is_domingo = TimeDayOfWeek(fecha_temp) == 0 ? contador=contador+1:NULL;
  if (contador == 4)
      {
    if(TimeDay(fecha_temp)>24)
        {
      ultimo_domingo = fecha_temp; 
      contador = 0;
        }
         else 
         {
         ultimo_domingo = fecha_temp + 7 * 60 * 60 * 24; 
         contador = 0;
         } 
      }
}

return ultimo_domingo;
}

datetime Ultimo_Domingo_Octubre(int year)
{
 datetime ultimo_domingo = 0;
 //datetime fecha = D'2022.10.01 10:00';
 datetime fecha = StrToTime(IntegerToString(year)+"."+"10"+"."+"01"+" "+"04:00");
 int contador = 0;
 for(int i=0;i<=31;i++)
 {
  datetime fecha_temp = fecha + (i*60*60*24);
  int is_domingo = TimeDayOfWeek(fecha_temp) == 0 ? contador=contador+1:NULL;
  if (contador == 4)
      {
       if(TimeDay(fecha_temp)>24)
        {
      ultimo_domingo = fecha_temp; 
      contador = 0;
        }
         else 
         {
         ultimo_domingo = fecha_temp + 7 * 60 * 60 * 24; 
         contador = 0;
         }      
      }
}

return ultimo_domingo;
}

datetime DST(datetime date)
{
   if (date >= Segundo_Domingo_Marzo(TimeYear(date)) && date < Primer_Domingo_Noviembre(TimeYear(date))){date = date - 3600;}
     else {date = date;}
return date;
}

datetime BST(datetime date)
{
   if (date >= Ultimo_Domingo_Marzo(TimeYear(date)) && date < Ultimo_Domingo_Octubre(TimeYear(date))) {date = date - 3600;}
     else date = date;
return date;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
 
@cmauro607 #:

I hope these functions help you. (Espero que estas funciones te ayuden.)

------------------------------------------------------------------------------------------------

Posible código alternativo a la función pre-establecida de MT4 TimeDaylightSavings() para determinar el cambio de horario verano/invierno para las zonas horarias de New York (DST - EDT) y Londres (BST) - Daylight Saving Time

Básicamente se busca detectar el segundo domingo de marzo y el primer domingo de noviembre para determinar el horario de verano para New York y el último domingo del mes de marzo y el último domingo de octubre para determinar el horario de verano para Londres. Una vez teniendo el rango de fechas, la función DST y BST devuelven la fecha ajustando una hora antes respecto a la hora del cliente terminal MT4 del broker. Es posible cambiar el retorno de una fecha a una validación booleana, de acuerdo a las necesidades de su código.

Entrada: datetime DST(fecha), BST(fecha)

Salida: Fecha modificada a -3600 segundos (1 hora) si está en horario de verano, o permanece igual si está en horario de invierno. Horarios en GMT+3 (BrokerTime)

This is the English forum so please post in English. Did you not notice that I translated your original post to English before you edited it again and added more text?
Reason: