//+------------------------------------------------------------------+ //| TimeSummer.mq5 | //| Copyright 2021, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "..\..\Include\PRTF.mqh" #include "..\..\Include\DateTime.mqh" #include //+------------------------------------------------------------------+ //| Server time zone and DST information | //+------------------------------------------------------------------+ struct ServerTime { int offsetGMT; // time zone offset in seconds against UTC/GMT int offsetDST; // DST correction in seconds (included in offsetGMT) bool supportDST; // DST changes are detected in the quotes string description; // textual explanation of result }; //+------------------------------------------------------------------+ //| Estimate server time zone and DST mode from H1 quotes history | //+------------------------------------------------------------------+ ServerTime ServerTimeZone(const string symbol = NULL) { const int year = 365 * 24 * 60 * 60; datetime array[]; if(PRTF(CopyTime(symbol, PERIOD_H1, TimeCurrent() - year, TimeCurrent(), array)) > 0) { // approx. 6000 bars should be acquired here const int n = ArraySize(array); PrintFormat("Got %d H1 bars, ~%d days", n, n / 24); int hours[24] = {}; int current = 0; for(int i = 0; i < n; ++i) { const ENUM_DAY_OF_WEEK weekday = TimeDayOfWeek(array[i]); // skip all days except Sunday and Monday if(weekday > MONDAY) continue; // lets analyze the first H1 bar of the trading week // find out an hour for the first bar after weekend current = _TimeHour(); // collect stats for opening hours hours[current]++; // now skip 2 days to check next week i += 48; } Print("Week opening hours stats:"); ArrayPrint(hours); if(hours[current] <= 52 / 4) { // TODO: refine results using previous weeks Print("Extraordinary week detected"); } // find most often time shift int max = ArrayMaximum(hours); // now check if a secondary time shift was also happened hours[max] = 0; int sub = ArrayMaximum(hours); // result variable init ServerTime st = {}; int DST = 0; // winter/summer periods are not equal! // summer time can be 8 months per year // 52 is the full year in weeks if(hours[sub] > 52 / 4) // DST is supported { if(current == max || current == sub) { if(current == MathMin(max, sub)) DST = fabs(max - sub); // DST is enabled now } st.supportDST = true; } current += 2 + DST; // +2 to get UTC offset // NB. when DST is enabled, time is shifted forward in the time zone, // but for outside it is looked like the time is shifted back // (everything in this time zone is happened earlier for others) // so to get standard time of the zone we need to add DST current %= 24; // time zones are in the range [UTC-12,UTC+12] if(current > 12) current = current - 24; current += DST; // if DST is enabled it's shown in offsetGMT according to MT5 rules st.description = StringFormat("Server time offset: UTC%+d, including DST%+d", current, DST); st.offsetGMT = -current * 3600; st.offsetDST = -DST * 3600; return st; } ServerTime empty = {-INT_MAX, -INT_MAX, false}; return empty; } #define HOUR 3600 #define DAY (24 * HOUR) #define WEEK 7 //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ datetime GetBarTime(const datetime time, const bool NextBar = false, string Symb = NULL, const ENUM_TIMEFRAMES TimeFrame = PERIOD_M1) { if (Symb == NULL) Symb = _Symbol; return(iTime(Symb, TimeFrame, iBarShift(Symb, TimeFrame, time) - (NextBar ? 1 : 0))); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ datetime GetTimeDayOfWeek(const int Shift = 0, const ENUM_DAY_OF_WEEK Day = SUNDAY) { const datetime Res = TimeCurrent() / DAY * DAY; return(Res - (((WEEK + (TimeDayOfWeek(Res) - Day)) % WEEK) + Shift * WEEK) * DAY); } // Аналог по серверному времени - https://www.mql5.com/ru/docs/dateandtime/timegmtoffset // Работает для FOREX-символов, когда M1-история доступна за ближайшую неделю int TimeServerGMTOffset( void ) { const datetime Sunday = GetTimeDayOfWeek(); return(((int)MathRound((double)MathMin(Sunday - DAY - GetBarTime(Sunday), Sunday + DAY - GetBarTime(Sunday, true)) / HOUR) - 3) * HOUR); } // Аналог по серверному времени - https://www.mql5.com/ru/docs/dateandtime/timegmt // Работает для FOREX-символов, когда M1-история доступна за ближайшую неделю datetime TimeServerGMT(void) { return(TimeCurrent() + TimeServerGMTOffset()); } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //PRTF(TimeLocal()); PRTF(TimeCurrent()); //PRTF(TimeTradeServer()); PRTF(TimeGMT()); PRTF(TimeGMTOffset()); PRTF(TimeDaylightSavings()); ServerTime st = ServerTimeZone(); Print(st.description); Print("ServerGMTOffset: ", st.offsetGMT); Print("ServerTimeDaylightSavings: ", st.offsetDST); Print("\n\n"); //--- //PRTF(TimeLocal()); PRTF(TimeCurrent()); //PRTF(TimeTradeServer()); PRTF(TimeGMT()); PRTF(TimeServerGMT()); Print("\n\n"); CTimeZoneInfo my_time(ZONE_ID_BROKER); ENUM_ZONE_ID id = ZONE_ID_UTC; PRTF(my_time.GetCurrentTimeForPlace(ZONE_ID_BROKER)); PRTF(my_time.GetCurrentTimeForPlace(ZONE_ID_UTC)); PRTF(my_time.GetCurrentTimeForPlace(ZONE_ID_LOCAL)); PRTF(my_time.ConvertTimeForPlace(TimeGMT(), ZONE_ID_UTC, ZONE_ID_BROKER)); PRTF(my_time.TimeLocal()); PRTF(my_time.TimeUTC()); PRTF(my_time.IsDaylightSavingTime(TimeCurrent() - PeriodSeconds(PERIOD_MN1) * 7, ZONE_ID_BROKER)); PRTF(my_time.IsDaylightSavingTime(TimeCurrent() - PeriodSeconds(PERIOD_MN1) * 7, ZONE_ID_UTC)); //datetime localtime = CTimeZoneInfo::GetCurrentTimeForPlace(id); //datetime converted = CTimeZoneInfo::ConvertTimeForPlace(localtime, id, ZONE_ID_BROKER); //PrintFormat("%-49s | %s", CTimeZoneInfo::FormatTimeForPlace(localtime, id), CTimeZoneInfo::FormatTimeForPlace(converted, ZONE_ID_BROKER)); } //+------------------------------------------------------------------+ /* example output MQ Demo (WARNING: TimeGMT != ServerGMT, because TimeGMT() - TimeCurrent() gives 3 hours difference, whereas ServerGMTOffset is 2 hours difference; probably DST is enabled all year round) TimeLocal()=2021.09.09 22:06:17 / ok TimeCurrent()=2021.09.09 22:06:10 / ok TimeTradeServer()=2021.09.09 22:06:17 / ok TimeGMT()=2021.09.09 19:06:17 / ok TimeGMTOffset()=-10800 / ok TimeDaylightSavings()=0 / ok CopyTime(symbol,PERIOD_H1,TimeCurrent()-year,TimeCurrent(),array)=6207 / ok Got 6207 H1 bars, ~258 days Week opening hours stats: 52 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Server time offset: UTC+2, including DST+0 ServerGMTOffset: -7200 ServerTimeDaylightSavings: 0 */ //+------------------------------------------------------------------+