TimeUtils/TimeUtils.mqh
2025-09-19 20:26:04 +00:00

1449 lines
124 KiB
MQL5

//+------------------------------------------------------------------+
//| TimeUtils.mqh |
//| Copyright © 2024, Amr Ali |
//| https://www.mql5.com/en/users/amrali |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2024, Amr Ali"
#property link "https://www.mql5.com/en/users/amrali"
#property version "1.55"
#property description "High-performance functions for dealing with time."
// Updates:
// 2024.12.03 - v.1.10 : Initial release.
// 2024.12.05 - v.1.15 : Added functions for business days and for Nth() weekday of the month. Optimized calculations in DaysInMonth() function.
// 2024.12.09 - v.1.20 : Added TimeFormat() function to format the time according to the passed string of tokens.
// 2024.12.09 - v.1.25 : Optimized calculations in TimeToStructFast() function.
// 2024.12.10 - v.1.30 : Optimized TimeFormat(), StartOfYear() and EndOfYear() functions. Updated descriptions of some functions.
// 2024.12.15 - v.1.35 : Optimized GetNthWeekdayInYearMonth() function.
// 2024.12.18 - v.1.40 : Added IsCurrentXXX(), IsToday(), IsTomorrow() and IsYesterday() functions.
// 2024.12.19 - v.1.45 : Optimized AddMonths() and GetNthWeekdayInYearMonth() functions.
// 2024.12.20 - v.1.50 : More code clean-up.
// 2024.12.21 - v.1.55 : Simplified calculations in AddMonths(): replaced the complex logic of adjusting months and years with a simpler total months calculation.
#ifdef __MQL4__
#property strict
#endif
#ifndef TIMEUTILS_UNIQUE_HEADER_ID_H
#define TIMEUTILS_UNIQUE_HEADER_ID_H
//#define TIMEUTILS_PERFORMANCE_MODE
//+------------------------------------------------------------------+
//| Performance mode |
//+------------------------------------------------------------------+
#ifdef TIMEUTILS_PERFORMANCE_MODE
// replace calls to MQL's built-in functions via macro substitutions.
#define TimeToStruct TimeToStructFast // 5x faster than TimeToStruct
#define StructToTime CreateDateTime // 30x faster than StructToTime
#endif
//+==================================================================+
//| Create datetime From Components |
//+==================================================================+
// datetime CreateDateTime(
// const int year, // Year
// const int mon, // Month
// const int day, // Day
// const int hour = 0, // Hour
// const int min = 0, // Minutes
// const int sec = 0 // Seconds
// )
// datetime CreateDateTime(MqlDateTime& dt_struct); // fast alternative to StructToTime()
//+==================================================================+
//| Break datetime To Components |
//+==================================================================+
// bool TimeToStructFast(
// datetime dt, // Date value to convert
// MqlDateTime& dt_struct // structure for the adoption of values
// )
//+==================================================================+
//| Extract Components of datetime: Sunday, yyyy.mm.dd hh:mm:ss |
//| Get() Units |
//+==================================================================+
// int GetSecond(datetime t)
// int GetMinute(datetime t)
// int GetHour(datetime t)
// int GetDay(datetime t)
// int GetMonth(datetime t)
// int GetYear(datetime t)
//+==================================================================+
//| Day() Number |
//+==================================================================+
// int DayOfWeek(datetime t)
// int DayOfYear(datetime t)
// int DayIndex(datetime t)
//+==================================================================+
//| Week() Number |
//+==================================================================+
// int WeekOfMonth(const datetime t, bool StartsOnMonday = false)
// int WeekOfYear(const datetime t, bool StartsOnMonday = false)
// int WeekIndex(datetime t, bool StartsOnMonday = false)
//+==================================================================+
//| StartOf() Units |
//+==================================================================+
// datetime StartOfMinute(datetime t)
// datetime StartOfHour(datetime t)
// datetime StartOfDay(datetime t)
// datetime StartOfWeek(datetime t, bool StartsOnMonday = false)
// datetime StartOfMonth(datetime t)
// datetime StartOfYear(datetime t)
//+==================================================================+
//| EndOf() Units |
//+==================================================================+
// datetime EndOfMinute(datetime t)
// datetime EndOfHour(datetime t)
// datetime EndOfDay(datetime t)
// datetime EndOfWeek(datetime t, bool StartsOnMonday = false)
// datetime EndOfMonth(datetime t)
// datetime EndOfYear(datetime t)
//+==================================================================+
//| SecsElapsedOf() Units |
//+==================================================================+
// int SecsElapsedOfMinute(datetime t)
// int SecsElapsedOfHour(datetime t)
// int SecsElapsedOfDay(datetime t)
// int SecsElapsedOfWeek(datetime t, bool StartsOnMonday = false)
// int SecsElapsedOfMonth(datetime t)
// int SecsElapsedOfYear(datetime t)
//+==================================================================+
//| RoundTo() / Nearest() Units |
//+==================================================================+
// datetime RoundToMinute(datetime t)
// datetime RoundToHour(datetime t)
// datetime RoundToDay(datetime t)
// datetime RoundToWeek(datetime t, bool StartsOnMonday = false)
//+==================================================================+
//| CeilTo() / Next() Units |
//+==================================================================+
// datetime CeilToMinute(datetime t)
// datetime CeilToHour(datetime t)
// datetime CeilToDay(datetime t)
// datetime CeilToWeek(datetime t, bool StartsOnMonday = false)
//+==================================================================+
//| Next() Weekday |
//+==================================================================+
// datetime NextWeekday(datetime t, ENUM_DAY_OF_WEEK weekday = SUNDAY)
// datetime NextSunday(datetime t)
// datetime NextMonday(datetime t)
// datetime NextTuesday(datetime t)
// datetime NextWednesday(datetime t)
// datetime NextThursday(datetime t)
// datetime NextFriday(datetime t)
// datetime NextSaturday(datetime t)
//+==================================================================+
//| Previous() Weekday |
//+==================================================================+
// datetime PreviousWeekday(datetime t, ENUM_DAY_OF_WEEK weekday = SUNDAY)
// datetime PreviousSunday(datetime t)
// datetime PreviousMonday(datetime t)
// datetime PreviousTuesday(datetime t)
// datetime PreviousWednesday(datetime t)
// datetime PreviousThursday(datetime t)
// datetime PreviousFriday(datetime t)
// datetime PreviousSaturday(datetime t)
//+==================================================================+
//| Nth() Weekday Of The Month |
//+==================================================================+
// datetime FirstWeekdayOfTheMonth(datetime t, ENUM_DAY_OF_WEEK weekday = SUNDAY)
// datetime LastWeekdayOfTheMonth(datetime t, ENUM_DAY_OF_WEEK weekday = SUNDAY)
// datetime NthWeekdayOfTheMonth(datetime t, int Nth, ENUM_DAY_OF_WEEK weekday = SUNDAY)
//+==================================================================+
//| Add() Units |
//+==================================================================+
// datetime AddSeconds(datetime t, int amount)
// datetime AddMinutes(datetime t, int amount)
// datetime AddHours(datetime t, int amount)
// datetime AddDays(datetime t, int amount)
// datetime AddBusinessDays(datetime t, int amount)
// datetime AddWeeks(datetime t, int amount)
// datetime AddMonths(datetime t, int amount)
// datetime AddYears(datetime t, int amount)
//+==================================================================+
//| Sub() Units |
//+==================================================================+
// datetime SubSeconds(datetime t, int amount)
// datetime SubMinutes(datetime t, int amount)
// datetime SubHours(datetime t, int amount)
// datetime SubDays(datetime t, int amount)
// datetime SubBusinessDays(datetime t, int amount)
// datetime SubWeeks(datetime t, int amount)
// datetime SubMonths(datetime t, int amount)
// datetime SubYears(datetime t, int amount)
//+==================================================================+
//| DifferenceIn() Units |
//+==================================================================+
// int DifferenceInCalendarDays(datetime beginTime, datetime endTime)
// int DifferenceInBusinessDays(datetime beginTime, datetime endTime)
// int DifferenceInCalendarWeeks(datetime beginTime, datetime endTime, bool StartsOnMonday = false)
// int DifferenceInCalendarMonths(datetime beginTime, datetime endTime)
//+==================================================================+
//| IsSame() Units |
//+==================================================================+
// bool IsSameMinute(datetime t1, datetime t2)
// bool IsSameHour(datetime t1, datetime t2)
// bool IsSameDay(datetime t1, datetime t2)
// bool IsSameWeek(datetime t1, datetime t2, bool StartsOnMonday = false)
// bool IsSameMonth(datetime t1, datetime t2)
// bool IsSameYear(datetime t1, datetime t2)
//+==================================================================+
//| IsCurrent() Units |
//+==================================================================+
// bool IsCurrentMinute(datetime t)
// bool IsCurrentHour(datetime t)
// bool IsCurrentWeek(datetime t, bool StartsOnMonday = false)
// bool IsCurrentMonth(datetime t)
// bool IsCurrentYear(datetime t)
// bool IsToday(datetime t)
// bool IsTomorrow(datetime t)
// bool IsYesterday(datetime t)
//+==================================================================+
//| Misc |
//+==================================================================+
// bool IsLeapYear(int year)
// int DaysInMonth(int year, int month)
// datetime GetNthWeekdayInYearMonth(iYear, iMonth, Nth, weekday = SUNDAY)
// datetime GetNthSundayInYearMonth(iYear, iMonth, Nth)
//+==================================================================+
//| Formating Time to String |
//+==================================================================+
// string t2s(datetime t, const int mode = TIME_DATE | TIME_MINUTES)
// string SecondsToString(int seconds)
// string TimeFormat(datetime t, string format = "YYYY.MM.DD hh:mm")
//+------------------------------------------------------------------+
//| Time unit constants |
//+------------------------------------------------------------------+
#define MINSECS 60
#define HOURSECS 3600
#define DAYSECS 86400
#define WEEKSECS 604800
#define YEARSECS 31536000
#define DAYSIN4YEARS 1461 // = (4 * 365) + 1
//+==================================================================+
//| Create datetime From Components |
//+==================================================================+
//+------------------------------------------------------------------+
//| Create a datetime value from the given year, month and day. |
//| https://www.mql5.com/en/forum/393227/page254#comment_53104384 |
//| Limit: Year must be <= 2100 |
//+------------------------------------------------------------------+
datetime CreateDateTime(
const int year, // Year
const int mon, // Month
const int day, // Day
const int hour = 0, // Hour
const int min = 0, // Minutes
const int sec = 0 // Seconds
)
{
// MqlDateTime dt = {year, mon, day, hour, min, sec}
// return StructToTime(dt);
static const uint Months[] = {0, 11512676, 11512180, 11511728, 11511232, 11510750, 11510256,
11509774, 11509280, 11508781, 11508302, 11507806, 11507326
};
return (((year * 5844 - Months[mon]) >> 4) + day - 1) * DAYSECS + (hour * HOURSECS + min * MINSECS + sec);
}
//+------------------------------------------------------------------+
//| The equivalent of MQL's built-in StructToTime() function. |
//| Converts a structure variable MqlDateTime into a value of |
//| datetime type and returns the resulting value containing |
//| the number of seconds since 01.01.1970. |
//+------------------------------------------------------------------+
datetime CreateDateTime(MqlDateTime& dt_struct)
{
return CreateDateTime(dt_struct.year, dt_struct.mon, dt_struct.day,
dt_struct.hour, dt_struct.min, dt_struct.sec);
}
//+==================================================================+
//| Break datetime To Components |
//+==================================================================+
//+------------------------------------------------------------------+
//| The equivalent of MQL's built-in TimeToStruct() function. |
//| Converts a value of datetime type (number of seconds |
//| since 01.01.1970) into a structure variable MqlDateTime. |
//+------------------------------------------------------------------+
bool TimeToStructFast(datetime dt, MqlDateTime& dt_struct)
{
static const int Months[13] = {0, -1, 30, 58, 89, 119, 150, 180, 211,242, 272, 303, 333};
static int last_days = -1;
static MqlDateTime last_result = {};
const uint t = (uint)dt;
const int n = (int)(t / DAYSECS);
if(last_days != n)
{
int tn = (n << 2) + 2;
int dow = (n + 4) % 7;
int doy = (tn % DAYSIN4YEARS) / 4;
int year = (tn / DAYSIN4YEARS) + 1970; // to 2100
int isleap = ((year & 3) == 0);
int leapadj = ((doy < (isleap + 59)) ? 0 : (2 - isleap));
//int mon = ((((doy + leapadj) * 12) + 373) / 367);
int mon = ((((doy + leapadj) * 67) + 2075) >> 11);
int day = doy - Months[mon] - (isleap && doy > 59);
last_days = n;
last_result.year = year;
last_result.mon = mon;
last_result.day = day;
last_result.day_of_week = dow;
last_result.day_of_year = doy;
}
dt_struct = last_result;
dt_struct.hour= (int)(t / HOURSECS) % 24;
dt_struct.min = (int)(t / MINSECS) % MINSECS;
dt_struct.sec = (int)(t % MINSECS);
return (true);
}
//+==================================================================+
//| Extract Components of datetime: Sunday, yyyy.mm.dd hh:mm:ss |
//| Get() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Return seconds of minute as integer (0..59) |
//+------------------------------------------------------------------+
int GetSecond(const datetime t)
{
return (int)((uint)t % MINSECS);
}
//+------------------------------------------------------------------+
//| Return minutes of hour as integer (0..59) |
//+------------------------------------------------------------------+
int GetMinute(const datetime t)
{
return (int)((uint)t / MINSECS) % MINSECS;
}
//+------------------------------------------------------------------+
//| Return hour of day as integer (0..23) |
//+------------------------------------------------------------------+
int GetHour(const datetime t)
{
return (int)((uint)t / HOURSECS) % 24;
}
//+------------------------------------------------------------------+
//| Return day of month as integer (1..31) |
//+------------------------------------------------------------------+
int GetDay(const datetime t)
{
MqlDateTime st;
TimeToStruct(t, st);
return(st.day);
}
//+------------------------------------------------------------------+
//| Return the month number as integer (1..12) |
//+------------------------------------------------------------------+
int GetMonth(const datetime t)
{
MqlDateTime st;
TimeToStruct(t, st);
return(st.mon);
}
//+------------------------------------------------------------------+
//| Returns year as integer of the given date (e.g., 2019) |
//| https://www.mql5.com/ru/forum/170952/page251#comment_53071746 |
//+------------------------------------------------------------------+
int GetYear(const datetime t)
{
return (int)(((uint)t / DAYSECS * 4 + 2) / DAYSIN4YEARS) + 1970;
}
//+==================================================================+
//| Day() Number |
//+==================================================================+
//+------------------------------------------------------------------+
//| Day of the week as integer (0-Sunday, 1-Monday, ... ,6-Saturday) |
//+------------------------------------------------------------------+
int DayOfWeek(const datetime t)
{
return (int)((uint)t / DAYSECS + THURSDAY) % 7; // 1 Jan 1970 is Thursday
}
//+------------------------------------------------------------------+
//| Get the zero-based day of the year as integer (0...365) |
//+------------------------------------------------------------------+
int DayOfYear(const datetime t)
{
return (int)(((uint)t / DAYSECS * 4 + 2) % DAYSIN4YEARS) / 4;
}
//+------------------------------------------------------------------+
//| Returns the zero-based absolute day number after 1 jan 1970 |
//+------------------------------------------------------------------+
//---This function can be useful in indicators for determining the first bar of the new day:
//---bool NewDay = DayIndex(time[i]) != DayIndex(time[i-1]);
int DayIndex(const datetime t)
{
return (int)(t / DAYSECS);
}
//+==================================================================+
//| Week() Number |
//+==================================================================+
//+------------------------------------------------------------------+
//| Get the week number of the month as integer (1...6) |
//| By default, the week starts on Sunday, unless superseded. |
//+------------------------------------------------------------------+
int WeekOfMonth(const datetime t, const bool StartsOnMonday = false)
{
int delta = (int)StartsOnMonday - DayOfWeek(StartOfMonth(t));
if (delta <= 0) delta += 7;
return ((GetDay(t) - delta + 6) / 7) + 1;
}
//+------------------------------------------------------------------+
//| Get the week number of the year as integer (1...53) |
//| By default, the week starts on Sunday, unless superseded. |
//+------------------------------------------------------------------+
int WeekOfYear(const datetime t, const bool StartsOnMonday = false)
{
int delta = (int)StartsOnMonday - DayOfWeek(StartOfYear(t));
if (delta <= 0) delta += 7;
return ((DayOfYear(t) - delta + 7) / 7) + 1;
}
//+------------------------------------------------------------------+
//| Returns the zero-based absolute week number since 1 Jan 1970 |
//| By default, the week starts on Sunday, unless superseded. |
//+------------------------------------------------------------------+
int WeekIndex(const datetime t, const bool StartsOnMonday = false)
{
int offset = (THURSDAY - StartsOnMonday) * DAYSECS; // 1 Jan 1970 is Thursday
return (int)((t + offset) / WEEKSECS);
}
//+==================================================================+
//| StartOf() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Return the start of a minute for the given date. |
//+------------------------------------------------------------------+
datetime StartOfMinute(const datetime t)
{
return t - (t % MINSECS);
}
//+------------------------------------------------------------------+
//| Return the start of an hour for the given date. |
//+------------------------------------------------------------------+
datetime StartOfHour(const datetime t)
{
return t - (t % HOURSECS);
}
//+------------------------------------------------------------------+
//| Return the start of a day for the given date. |
//+------------------------------------------------------------------+
datetime StartOfDay(const datetime t)
{
return t - (t % DAYSECS);
}
//+------------------------------------------------------------------+
//| Return the start of a week for the given date. |
//| By default, the week starts on Sunday, unless superseded. |
//| |
//| StartOfWeek (D'2017.08.03 11:30') => 2017.07.30 00:00:00 |
//+------------------------------------------------------------------+
datetime StartOfWeek(const datetime t, const bool StartsOnMonday = false)
{
int offset = (THURSDAY - StartsOnMonday) * DAYSECS; // 1 Jan 1970 is Thursday
return t - ((t + offset) % WEEKSECS);
}
//+------------------------------------------------------------------+
//| Return the start of a month for the given date. |
//+------------------------------------------------------------------+
datetime StartOfMonth(const datetime t)
{
MqlDateTime st;
TimeToStruct(t, st);
st.day = 1;
st.hour = 0;
st.min = 0;
st.sec = 0;
return StructToTime(st);
}
//+------------------------------------------------------------------+
//| Return the start of a year for the given date. |
//+------------------------------------------------------------------+
datetime StartOfYear(const datetime t)
{
const int year = GetYear(t);
MqlDateTime st = {year, 1, 1};
return StructToTime(st);
}
//+==================================================================+
//| EndOf() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Return the last second of a minute for the given date. |
//+------------------------------------------------------------------+
datetime EndOfMinute(const datetime t)
{
return StartOfMinute(t) + (MINSECS - 1);
}
//+------------------------------------------------------------------+
//| Return the last second of an hour for the given date. |
//+------------------------------------------------------------------+
datetime EndOfHour(const datetime t)
{
return StartOfHour(t) + (HOURSECS - 1);
}
//+------------------------------------------------------------------+
//| Return the last second of a day for the given date. |
//+------------------------------------------------------------------+
datetime EndOfDay(const datetime t)
{
return StartOfDay(t) + (DAYSECS - 1);
}
//+------------------------------------------------------------------+
//| Return the last second of a week for the given date. |
//| By default, the week starts on Sunday, unless superseded. |
//+------------------------------------------------------------------+
datetime EndOfWeek(const datetime t, const bool StartsOnMonday = false)
{
return StartOfWeek(t, StartsOnMonday) + (WEEKSECS - 1);
}
//+------------------------------------------------------------------+
//| Return the last second of a month for the given date. |
//+------------------------------------------------------------------+
datetime EndOfMonth(const datetime t)
{
// MqlDateTime st;
// TimeToStruct(t, st);
// st.day = DaysInMonth(st.year, st.mon);
// st.hour = 23;
// st.min = 59;
// st.sec = 59;
// return(StructToTime(st));
MqlDateTime st;
TimeToStruct(t, st);
st.year += (st.mon == 12);
st.mon = (st.mon % 12) + 1;
st.day = 1;
st.hour = 0;
st.min = 0;
st.sec = 0;
return StructToTime(st) - 1;
}
//+------------------------------------------------------------------+
//| Return the last second of a year for the given date. |
//+------------------------------------------------------------------+
datetime EndOfYear(const datetime t)
{
const int nextyear = GetYear(t) + 1;
MqlDateTime st = {nextyear, 1, 1};
return StructToTime(st) - 1;
}
//+==================================================================+
//| SecsElapsedOf() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of minute for the given date. |
//+------------------------------------------------------------------+
int SecsElapsedOfMinute(const datetime t)
{
// return (int)(t - StartOfMinute(t));
return (int)(t % MINSECS);
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of hour for the given date. |
//+------------------------------------------------------------------+
int SecsElapsedOfHour(const datetime t)
{
// return (int)(t - StartOfHour(t));
return (int)(t % HOURSECS);
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of day for the given date. |
//+------------------------------------------------------------------+
int SecsElapsedOfDay(const datetime t)
{
// return (int)(t - StartOfDay(t));
return (int)(t % DAYSECS);
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of week for the given date. |
//| By default, the week starts on Sunday, unless superseded. |
//+------------------------------------------------------------------+
int SecsElapsedOfWeek(const datetime t, const bool StartsOnMonday = false)
{
return (int)(t - StartOfWeek(t, StartsOnMonday));
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of month for the given date. |
//+------------------------------------------------------------------+
int SecsElapsedOfMonth(const datetime t)
{
return (int)(t - StartOfMonth(t));
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of year for the given date. |
//+------------------------------------------------------------------+
int SecsElapsedOfYear(const datetime t)
{
return (int)(t - StartOfYear(t));
}
//+==================================================================+
//| RoundTo() / Nearest() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Rounds halfway the given date to the nearest minute. |
//+------------------------------------------------------------------+
datetime RoundToMinute(const datetime t)
{
return StartOfMinute(t + MINSECS / 2);
}
//+------------------------------------------------------------------+
//| Rounds halfway the given date to the nearest hour. |
//+------------------------------------------------------------------+
datetime RoundToHour(const datetime t)
{
return StartOfHour(t + HOURSECS / 2);
}
//+------------------------------------------------------------------+
//| Rounds halfway the given date to the nearest day. |
//+------------------------------------------------------------------+
datetime RoundToDay(const datetime t)
{
return StartOfDay(t + DAYSECS / 2);
}
//+------------------------------------------------------------------+
//| Rounds halfway the given date to the nearest week. |
//| By default, the week starts on Sunday, unless superseded. |
//+------------------------------------------------------------------+
datetime RoundToWeek(const datetime t, const bool StartsOnMonday = false)
{
return StartOfWeek(t + WEEKSECS / 2, StartsOnMonday);
}
//+==================================================================+
//| CeilTo() / Next() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Rounds up the given date to the next minute. |
//+------------------------------------------------------------------+
datetime CeilToMinute(const datetime t)
{
return StartOfMinute(t + MINSECS - 1);
}
//+------------------------------------------------------------------+
//| Rounds up the given date to the next hour. |
//+------------------------------------------------------------------+
datetime CeilToHour(const datetime t)
{
return StartOfHour(t + HOURSECS - 1);
}
//+------------------------------------------------------------------+
//| Rounds up the given date to the next day. |
//+------------------------------------------------------------------+
datetime CeilToDay(const datetime t)
{
return StartOfDay(t + DAYSECS - 1);
}
//+------------------------------------------------------------------+
//| Rounds up the given date to the next week. |
//| By default, the week starts on Sunday, unless superseded. |
//+------------------------------------------------------------------+
datetime CeilToWeek(const datetime t, const bool StartsOnMonday = false)
{
return StartOfWeek(t + WEEKSECS - 1, StartsOnMonday);
}
//+==================================================================+
//| Next() Weekday |
//+==================================================================+
//+------------------------------------------------------------------+
//| Return the next day of the week after the given date. |
//+------------------------------------------------------------------+
datetime NextWeekday(const datetime t, const ENUM_DAY_OF_WEEK weekday = SUNDAY)
{
int delta = weekday - DayOfWeek(t);
if (delta <= 0) delta += 7;
return StartOfDay(t + delta * DAYSECS);
}
//+------------------------------------------------------------------+
//| When is the next Sunday? |
//+------------------------------------------------------------------+
datetime NextSunday(const datetime t)
{
return NextWeekday(t, SUNDAY);
}
//+------------------------------------------------------------------+
//| When is the next Monday? |
//+------------------------------------------------------------------+
datetime NextMonday(const datetime t)
{
return NextWeekday(t, MONDAY);
}
//+------------------------------------------------------------------+
//| When is the next Tuesday? |
//+------------------------------------------------------------------+
datetime NextTuesday(const datetime t)
{
return NextWeekday(t, TUESDAY);
}
//+------------------------------------------------------------------+
//| When is the next Wednesday? |
//+------------------------------------------------------------------+
datetime NextWednesday(const datetime t)
{
return NextWeekday(t, WEDNESDAY);
}
//+------------------------------------------------------------------+
//| When is the next Thursday? |
//+------------------------------------------------------------------+
datetime NextThursday(const datetime t)
{
return NextWeekday(t, THURSDAY);
}
//+------------------------------------------------------------------+
//| When is the next Friday? |
//+------------------------------------------------------------------+
datetime NextFriday(const datetime t)
{
return NextWeekday(t, FRIDAY);
}
//+------------------------------------------------------------------+
//| When is the next Saturday? |
//+------------------------------------------------------------------+
datetime NextSaturday(const datetime t)
{
return NextWeekday(t, SATURDAY);
}
//+==================================================================+
//| Previous() Weekday |
//+==================================================================+
//+------------------------------------------------------------------+
//| Return the previous day of the week before the given date. |
//+------------------------------------------------------------------+
datetime PreviousWeekday(const datetime t, const ENUM_DAY_OF_WEEK weekday = SUNDAY)
{
int delta = DayOfWeek(t) - weekday;
if (delta <= 0) delta += 7;
return StartOfDay(t - delta * DAYSECS);
}
//+------------------------------------------------------------------+
//| When is the previous Sunday? |
//+------------------------------------------------------------------+
datetime PreviousSunday(const datetime t)
{
return PreviousWeekday(t, SUNDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Monday? |
//+------------------------------------------------------------------+
datetime PreviousMonday(const datetime t)
{
return PreviousWeekday(t, MONDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Tuesday? |
//+------------------------------------------------------------------+
datetime PreviousTuesday(const datetime t)
{
return PreviousWeekday(t, TUESDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Wednesday? |
//+------------------------------------------------------------------+
datetime PreviousWednesday(const datetime t)
{
return PreviousWeekday(t, WEDNESDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Thursday? |
//+------------------------------------------------------------------+
datetime PreviousThursday(const datetime t)
{
return PreviousWeekday(t, THURSDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Friday? |
//+------------------------------------------------------------------+
datetime PreviousFriday(const datetime t)
{
return PreviousWeekday(t, FRIDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Saturday? |
//+------------------------------------------------------------------+
datetime PreviousSaturday(const datetime t)
{
return PreviousWeekday(t, SATURDAY);
}
//+==================================================================+
//| Nth() Weekday Of The Month |
//+==================================================================+
//+------------------------------------------------------------------+
//| Return the first day of the week of the month of the given date. |
//+------------------------------------------------------------------+
datetime FirstWeekdayOfTheMonth(const datetime t, const ENUM_DAY_OF_WEEK weekday = SUNDAY)
{
return GetNthWeekdayInYearMonth(GetYear(t), GetMonth(t), 1, weekday);
}
//+------------------------------------------------------------------+
//| Return the last day of the week of the month of the given date. |
//+------------------------------------------------------------------+
datetime LastWeekdayOfTheMonth(const datetime t, const ENUM_DAY_OF_WEEK weekday = SUNDAY)
{
return GetNthWeekdayInYearMonth(GetYear(t), GetMonth(t), 5, weekday);
}
//+------------------------------------------------------------------+
//| Return the "Nth" day of the week of the month of the given date. |
//+------------------------------------------------------------------+
datetime NthWeekdayOfTheMonth(const datetime t, const int Nth, const ENUM_DAY_OF_WEEK weekday = SUNDAY)
{
return GetNthWeekdayInYearMonth(GetYear(t), GetMonth(t), Nth, weekday);
}
//+==================================================================+
//| Add() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Add the specified number of seconds to the given date. |
//+------------------------------------------------------------------+
datetime AddSeconds(const datetime t, const int amount)
{
return t + amount;
}
//+------------------------------------------------------------------+
//| Add the specified number of minutes to the given date. |
//+------------------------------------------------------------------+
datetime AddMinutes(const datetime t, const int amount)
{
return t + (amount * MINSECS);
}
//+------------------------------------------------------------------+
//| Add the specified number of hours to the given date. |
//+------------------------------------------------------------------+
datetime AddHours(const datetime t, const int amount)
{
return t + (amount * HOURSECS);
}
//+------------------------------------------------------------------+
//| Add the specified number of days to the given date. |
//+------------------------------------------------------------------+
datetime AddDays(const datetime t, const int amount)
{
return t + (amount * DAYSECS);
}
//+------------------------------------------------------------------+
//| Add the specified number of business days (Mon - Fri) to the |
//| given date, ignoring weekends. |
//+------------------------------------------------------------------+
datetime AddBusinessDays(const datetime t, const int amount)
{
datetime dt_result = t;
int step = amount < 0 ? -1 : 1;
int added = 0;
while(added < MathAbs(amount))
{
dt_result = AddDays(dt_result, step);
int dow = DayOfWeek(dt_result);
// Use modulo operator to check for weekends more efficiently
if(dow % 6 != 0)
{
added++;
}
}
return dt_result;
}
//+------------------------------------------------------------------+
//| Add the specified number of weeks to the given date. |
//+------------------------------------------------------------------+
datetime AddWeeks(const datetime t, const int amount)
{
return t + (amount * WEEKSECS);
}
//+------------------------------------------------------------------+
//| Add the specified number of months to the given date. |
//+------------------------------------------------------------------+
datetime AddMonths(const datetime t, const int amount)
{
MqlDateTime st;
TimeToStruct(t, st);
int totalMonths = st.year * 12 + (st.mon - 1) + amount; // month is 1-based
st.year = totalMonths / 12;
st.mon = (totalMonths % 12) + 1;
st.day = MathMin(st.day, DaysInMonth(st.year, st.mon));
return StructToTime(st);
}
//+------------------------------------------------------------------+
//| Add the specified number of years to the given date. |
//+------------------------------------------------------------------+
datetime AddYears(const datetime t, const int amount)
{
return AddMonths(t, amount * 12);
}
//+==================================================================+
//| Sub() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Subtract the specified number of seconds from the given date. |
//+------------------------------------------------------------------+
datetime SubSeconds(const datetime t, const int amount)
{
return AddSeconds(t, -amount);
}
//+------------------------------------------------------------------+
//| Subtract the specified number of minutes from the given date. |
//+------------------------------------------------------------------+
datetime SubMinutes(const datetime t, const int amount)
{
return AddMinutes(t, -amount);
}
//+------------------------------------------------------------------+
//| Subtract the specified number of hours from the given date. |
//+------------------------------------------------------------------+
datetime SubHours(const datetime t, const int amount)
{
return AddHours(t, -amount);
}
//+------------------------------------------------------------------+
//| Subtract the specified number of days from the given date. |
//+------------------------------------------------------------------+
datetime SubDays(const datetime t, const int amount)
{
return AddDays(t, -amount);
}
//+------------------------------------------------------------------+
//| Subtract the specified number of business days (mon - fri) |
//| from the given date, ignoring weekends. |
//+------------------------------------------------------------------+
datetime SubBusinessDays(const datetime t, const int amount)
{
return AddBusinessDays(t, -amount);
}
//+------------------------------------------------------------------+
//| Subtract the specified number of weeks from the given date. |
//+------------------------------------------------------------------+
datetime SubWeeks(const datetime t, const int amount)
{
return AddWeeks(t, -amount);
}
//+------------------------------------------------------------------+
//| Subtract the specified number of months from the given date. |
//+------------------------------------------------------------------+
datetime SubMonths(const datetime t, const int amount)
{
return AddMonths(t, -amount);
}
//+------------------------------------------------------------------+
//| Subtract the specified number of years from the given date. |
//+------------------------------------------------------------------+
datetime SubYears(const datetime t, const int amount)
{
return AddYears(t, -amount);
}
//+==================================================================+
//| DifferenceIn() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Get the number of calendar days between the given dates. |
//| the difference in days is calculated after removing times. |
//+------------------------------------------------------------------+
int DifferenceInCalendarDays(const datetime beginTime, const datetime endTime)
{
return DayIndex(endTime) - DayIndex(beginTime);
}
//+------------------------------------------------------------------+
//| Get the number of business days (Mon - Fri) between the given |
//| dates, excluding weekends. The end date is not included. |
//+------------------------------------------------------------------+
int DifferenceInBusinessDays(const datetime beginTime, const datetime endTime)
{
datetime dt_temp = beginTime;
int step = endTime < beginTime ? -1 : 1;
int diff = 0;
while(!IsSameDay(dt_temp, endTime))
{
int dow = DayOfWeek(dt_temp);
// Use modulo operator to check for weekends more efficiently
if(dow % 6 != 0)
{
diff++;
}
dt_temp = AddDays(dt_temp, step);
}
return diff;
}
//+------------------------------------------------------------------+
//| Get the number of calendar weeks between the given dates. |
//| the difference in weeks is calculated after removing days. |
//| By default, the week starts on Sunday, unless superseded. |
//+------------------------------------------------------------------+
int DifferenceInCalendarWeeks(const datetime beginTime, const datetime endTime, const bool StartsOnMonday = false)
{
return WeekIndex(endTime, StartsOnMonday) - WeekIndex(beginTime, StartsOnMonday);
}
//+------------------------------------------------------------------+
//| Get the number of calendar months between the given dates. |
//| the difference in months is calculated after removing days. |
//+------------------------------------------------------------------+
int DifferenceInCalendarMonths(const datetime beginTime, const datetime endTime)
{
const int yearsDiff = GetYear(endTime) - GetYear(beginTime);
const int monthsDiff = GetMonth(endTime) - GetMonth(beginTime);
return yearsDiff * 12 + monthsDiff;
}
//+==================================================================+
//| IsSame() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Are the given dates in the same minute (and hour and day)? |
//+------------------------------------------------------------------+
bool IsSameMinute(const datetime t1, const datetime t2)
{
return StartOfMinute(t1) == StartOfMinute(t2);
}
//+------------------------------------------------------------------+
//| Are the given dates in the same hour (and same day)? |
//+------------------------------------------------------------------+
bool IsSameHour(const datetime t1, const datetime t2)
{
return StartOfHour(t1) == StartOfHour(t2);
}
//+------------------------------------------------------------------+
//| Are the given dates in the same day (and year and month)? |
//+------------------------------------------------------------------+
bool IsSameDay(const datetime t1, const datetime t2)
{
// return DayIndex(t1) == DayIndex(t2);
return StartOfDay(t1) == StartOfDay(t2);
}
//+------------------------------------------------------------------+
//| Are the given dates in the same week (and month and year)? |
//| By default, the week starts on Sunday, unless superseded. |
//+------------------------------------------------------------------+
bool IsSameWeek(const datetime t1, const datetime t2, const bool StartsOnMonday = false)
{
return StartOfWeek(t1, StartsOnMonday) == StartOfWeek(t2, StartsOnMonday);
}
//+------------------------------------------------------------------+
//| Are the given dates in the same month (and year)? |
//+------------------------------------------------------------------+
bool IsSameMonth(const datetime t1, const datetime t2)
{
return GetYear(t1) == GetYear(t2) && GetMonth(t1) == GetMonth(t2);
}
//+------------------------------------------------------------------+
//| Are the given dates in the same year? |
//+------------------------------------------------------------------+
bool IsSameYear(const datetime t1, const datetime t2)
{
return GetYear(t1) == GetYear(t2);
}
//+==================================================================+
//| IsCurrent() Units |
//+==================================================================+
//+------------------------------------------------------------------+
//| Is the given date in the same minute as the current server time |
//+------------------------------------------------------------------+
bool IsCurrentMinute(const datetime t)
{
return IsSameMinute(t, TimeCurrent());
}
//+------------------------------------------------------------------+
//| Is the given date in the same hour as the current server time |
//+------------------------------------------------------------------+
bool IsCurrentHour(const datetime t)
{
return IsSameHour(t, TimeCurrent());
}
//+------------------------------------------------------------------+
//| Is the given date in the same week as the current server time |
//| By default, the week starts on Sunday, unless superseded. |
//+------------------------------------------------------------------+
bool IsCurrentWeek(const datetime t, const bool StartsOnMonday = false)
{
return IsSameWeek(t, TimeCurrent(), StartsOnMonday);
}
//+------------------------------------------------------------------+
//| Is the given date in the same month as the current server time |
//+------------------------------------------------------------------+
bool IsCurrentMonth(const datetime t)
{
return IsSameMonth(t, TimeCurrent());
}
//+------------------------------------------------------------------+
//| Is the given date in the same year as the current server time |
//+------------------------------------------------------------------+
bool IsCurrentYear(const datetime t)
{
return IsSameYear(t, TimeCurrent());
}
//+------------------------------------------------------------------+
//| Is the given date today on the trade server |
//+------------------------------------------------------------------+
bool IsToday(const datetime t)
{
return IsSameDay(t, TimeCurrent());
}
//+------------------------------------------------------------------+
//| Is the given date tomorrow on the trade server |
//+------------------------------------------------------------------+
bool IsTomorrow(const datetime t)
{
return IsSameDay(t, AddDays(TimeCurrent(), 1));
}
//+------------------------------------------------------------------+
//| Is the given date yesterday on the trade server |
//+------------------------------------------------------------------+
bool IsYesterday(const datetime t)
{
return IsSameDay(t, SubDays(TimeCurrent(), 1));
}
//+==================================================================+
//| Misc |
//+==================================================================+
//+------------------------------------------------------------------+
//| Checks whether the given year is a leap year or not |
//+------------------------------------------------------------------+
bool IsLeapYear(const int year)
{
//return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
// From: https://www.youtube.com/watch?v=0s9F4QWAl-E&t=1790s
return (year & ((year % 100 != 0) ? 3 : 15)) == 0;
}
//+------------------------------------------------------------------+
//| Get the number of days in a month of the given year. |
//+------------------------------------------------------------------+
int DaysInMonth(const int year, const int month)
{
//const int dim[13] = {0, 31, (IsLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//return dim[month % 13];
// From: https://www.youtube.com/watch?v=0s9F4QWAl-E&t=1790s
if(month == 2)
return 28 + IsLeapYear(year);
return 30 | (month ^ (month >> 3));
}
//+-------------------------------------------------------------------+
//| Return the date for the "Nth" weekday for the iYear and iMonth. |
//| If "Nth" is larger than the number of Weekdays in the month, |
//| return the last weekday. If "Nth" is otherwise invalid, return 0. |
//+-------------------------------------------------------------------+
datetime GetNthWeekdayInYearMonth(int iYear, int iMonth, int Nth, ENUM_DAY_OF_WEEK weekday = SUNDAY)
{
MqlDateTime st = {iYear, iMonth, 1};
datetime dt = StructToTime(st); // get date of first of month
datetime eom = dt + DaysInMonth(iYear, iMonth) * DAYSECS - 1;
if(Nth < 1) return 0;
if(Nth > 5) Nth = 5;
dt = AddDays(dt, -1);
dt = NextWeekday(dt, weekday); // move to 1st weekday of month
dt = AddWeeks(dt, Nth - 1);
dt = SubWeeks(dt, dt >= eom); // decrease one week if next month
return dt;
}
//+------------------------------------------------------------------+
//| Return the date for the "Nth" Sunday for the iYear and iMonth. |
//+------------------------------------------------------------------+
datetime GetNthSundayInYearMonth(int iYear, int iMonth, int Nth)
{
return GetNthWeekdayInYearMonth(iYear, iMonth, Nth, SUNDAY);
}
//+==================================================================+
//| Formating Time to String |
//+==================================================================+
//+------------------------------------------------------------------+
//| Formats time with the weekday name => "Wed, 2023.02.14 01:59" |
//+------------------------------------------------------------------+
string t2s(const datetime t, const int mode = TIME_DATE | TIME_MINUTES)
{
const string days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const int i = DayOfWeek(t);
return days[i % 7] + ", " + TimeToString(t, mode);
}
//+------------------------------------------------------------------+
//| Format the time in seconds to a string (like 2d 14:58:04) |
//+------------------------------------------------------------------+
string SecondsToString(const int seconds)
{
const int days = (int)(seconds / DAYSECS);
const string d = days ? (string)days + "d " : "";
return d + TimeToString(seconds, TIME_SECONDS);
}
//+------------------------------------------------------------------+
//| Returns the month name for a month number [1-12] |
//+------------------------------------------------------------------+
string MonthName(const int monthNo)
{
const static string months[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
return months[(uint)(monthNo - 1) % 12];
}
//+------------------------------------------------------------------+
//| Returns the weekday name for a weekday number [0-6] |
//+------------------------------------------------------------------+
string DayName(const int dayNo)
{
const static string days[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
return days[(uint)dayNo % 7];
}
//+------------------------------------------------------------------+
//| Get the formatted time according to the passed string of tokens. |
//| List of all available formats: |
//| Format Output Description |
//| ------ ---------------- ------------------------------------- |
//| YY 18 Two-digit year |
//| YYYY 2018 Four-digit year |
//| M 1-12 The month, beginning at 1 |
//| MM 01-12 The month, 2-digits |
//| MMM Jan-Dec The abbreviated month name, 3-letters |
//| MMMM January-December The full month name |
//| D 1-31 The day of the month |
//| DD 01-31 The day of the month, 2-digits |
//| DDD Sun-Sat The short name of the day of the week |
//| DDDD Sunday-Saturday The name of the day of the week |
//| h 0-23 The hour |
//| hh 00-23 The hour, 2-digits |
//| H 1-12 The hour, 12-hour clock |
//| HH 01-12 The hour, 12-hour clock, 2-digits |
//| m 0-59 The minute |
//| mm 00-59 The minute, 2-digits |
//| s 0-59 The second |
//| ss 00-59 The second, 2-digits |
//| A AM PM |
//| a am pm |
//+------------------------------------------------------------------+
//| Sample formats: |
//| "YYYY.MM.DD hh:mm" // "2024.12.08 22:05" (default) |
//| "DDD, YYYY.MM.DD hh:mm:ss" // "Sun, 2024.12.08 22:05:21" |
//| "D MMMM YYYY, HH:mm a" // "8 December 2024, 10:05 pm" |
//| "DD/MM/YYYY" // "08/12/2024" |
//+------------------------------------------------------------------+
string TimeFormat(const datetime t, const string format = "YYYY.MM.DD hh:mm") {
string retVal;
MqlDateTime dt_struct;
if(format == "" || StringLen(format) == 0) {
Print("invalid format");
return "";
}
if(TimeToStruct(t, dt_struct) == false) {
Print("TimeToStruct() failed. Error ", GetLastError());
return "";
}
string token = "";
int index_char = 0;
while (index_char < StringLen(format)) {
// get next token from format string
do {
token += StringSubstr(format, index_char, 1);
index_char++;
} while (index_char < StringLen(format) && format[index_char] == token[StringLen(token) - 1]);
// format datetime value based on format token
if(token == "YYYY") {
retVal += IntegerToString(dt_struct.year);
} else if(token == "YY") {
retVal += IntegerToString(dt_struct.year % 100, 2, '0');
} else if(token == "MMMM") {
retVal += MonthName(dt_struct.mon);
} else if(token == "MMM") {
retVal += StringSubstr(MonthName(dt_struct.mon), 0, 3);
} else if(token == "MM") {
retVal += IntegerToString(dt_struct.mon, 2, '0');
} else if(token == "M") {
retVal += IntegerToString(dt_struct.mon);
} else if(token == "DDDD") {
retVal += DayName(dt_struct.day_of_week);
} else if(token == "DDD") {
retVal += StringSubstr(DayName(dt_struct.day_of_week), 0, 3);
} else if(token == "DD") {
retVal += IntegerToString(dt_struct.day, 2, '0');
} else if(token == "D") {
retVal += IntegerToString(dt_struct.day);
} else if(token == "hh") {
retVal += IntegerToString(dt_struct.hour, 2, '0');
} else if(token == "h") {
retVal += IntegerToString(dt_struct.hour);
} else if(token == "HH") {
retVal += IntegerToString((bool)(dt_struct.hour % 12) ? dt_struct.hour % 12 : 12, 2, '0');
} else if(token == "H") {
retVal += IntegerToString((bool)(dt_struct.hour % 12) ? dt_struct.hour % 12 : 12);
} else if(token == "mm") {
retVal += IntegerToString(dt_struct.min, 2, '0');
} else if(token == "m") {
retVal += IntegerToString(dt_struct.min);
} else if(token == "ss") {
retVal += IntegerToString(dt_struct.sec, 2, '0');
} else if(token == "s") {
retVal += IntegerToString(dt_struct.sec);
} else if(token == "A") {
retVal += dt_struct.hour < 12 ? "AM" : "PM";
} else if(token == "a") {
retVal += dt_struct.hour < 12 ? "am" : "pm";
} else { // if there are any non-matching characters left in format string
retVal += token;
}
token = "";
}
return (retVal);
}
#undef MINSECS
#undef HOURSECS
#undef DAYSECS
#undef WEEKSECS
#undef YEARSECS
#undef DAYSIN4YEARS
#endif // #ifndef TIMEUTILS_UNIQUE_HEADER_ID_H
//+------------------------------------------------------------------+
/*
example code:
#include "TimeUtils.mqh"
void OnStart()
{
datetime t = TimeLocal();
Print( t2s(t, TIME_DATE|TIME_SECONDS) ); // Formats time with the weekday name
Print( GetYear(t) );
Print( GetMonth(t) );
Print( GetDay(t) );
Print( GetHour(t) );
Print( GetMinute(t) );
Print( GetSecond(t) );
Print( DayOfWeek(t) );
Print( DayOfYear(t) );
MqlDateTime st[1] = {};
TimeToStructFast(t, st[0]);
ArrayPrint(st);
st[0].year += 1;
Print(CreateDateTime(st[0]));
}
example output:
Tue, 2024.12.03 20:46:58
2024
12
3
20
46
58
2
337
[year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
[0] 2024 12 3 20 46 58 2 337
2025.12.03 20:46:58
*/
//+------------------------------------------------------------------+