TimeUtils/TimeUtils.mqh

2852 lines
123 KiB
MQL5
Raw Permalink Normal View History

2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| TimeUtils.mqh |
//| Copyright © 2026, Amr Ali |
//| https://www.mql5.com/en/users/amrali |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2026, Amr Ali"
#property link "https://www.mql5.com/en/users/amrali"
2026-08-10 15:28:29 +03:00
#property version "2.65"
2026-07-18 23:27:05 +03:00
#property description "High-performance functions for dealing with time."
// Updates:
2026-07-20 07:45:57 +03:00
// 2024.12.03 - v1.10 : Initial release.
// 2024.12.05 - v1.15 : Added functions for business days and for Nth() weekday of the month. Optimized calculations in DaysInMonth() function.
// 2024.12.09 - v1.20 : Added TimeFormat() function to format the time according to the passed string of tokens.
// 2024.12.09 - v1.25 : Optimized calculations in TimeToStructFast() function.
// 2024.12.10 - v1.30 : Optimized TimeFormat(), StartOfYear() and EndOfYear() functions. Updated descriptions of some functions.
// 2024.12.15 - v1.35 : Optimized NthWeekdayOfYearMonth() function.
// 2024.12.18 - v1.40 : Added IsCurrentXXX(), IsToday(), IsTomorrow() and IsYesterday() functions.
// 2024.12.19 - v1.45 : Optimized AddMonths() and NthWeekdayOfYearMonth() functions.
// 2024.12.20 - v1.50 : More code clean-up.
// 2024.12.21 - v1.55 : Simplified calculations in AddMonths(): replaced the complex logic of adjusting months and years with a simpler total months calculation.
// 2026.06.22 - v1.60 : Optimized AddBusinessDays() and DifferenceInBusinessDays() functions. Added various IsXXX() check functions.
// 2026.07.06 - v2.00 : New March-based conversion routines derived from the Neri–Schneider calendar algorithm + validation script. Removed "performance" mode.
// 2026.07.07 - v2.10 : Added DaysInYear(), LastDayOf(), MinuteOf(), HourOf() and CalendarDifferenceToString() functions.
// 2026.07.10 - v2.30 : Added date construction, quarter, calendar difference, and relative-date helper functions. Introduced configurable week start and renamed several functions for a cleaner, more consistent API.
// 2026.07.12 - v2.35 : Updated CalendarDifferenceToString() to return the precise elapsed time, including hours, minutes, and seconds.
// 2026.07.14 - v2.40 : Redesigned the year/month decomposition in CalendarDifferenceToString() to correctly handle February 29 edge cases. Simplified and optimized the DifferenceInXXX() functions. Added epoch-based index functions.
// 2026.07.15 - v2.45 : Added CalendarDifference() to return the calendar difference between two dates, broken down into years, months, days, hours, minutes, and seconds.
// 2026.07.18 - v2.50 : Added AddPeriod() and SubPeriod() for calendar period arithmetic. Added WithXxx() functions for replacing individual date/time fields. Added IsInSession() for checking recurring daily sessions.
// 2026.07.20 - v2.55 : Optimized week-based functions. Added SessionOverlap() for calculating overlapping time intervals. Improved documentation and API comments.
2026-07-21 21:05:41 +03:00
// 2026.07.21 - v2.60 : Added comprehensive Trading Sessions (IsInSession, IsInMarketSession, IsSessionOverlap, CurrentMarketSession, MarketSessionName) and Economic Calendar (IsNearNews, TimeUntilNews) utilities, plus NextOrSame()/PreviousOrSame() for inclusive weekday navigation. Code cleanup and documentation improvements.
2026-08-10 15:28:29 +03:00
// 2026.08.10 - v2.65 : Code cleanup and documentation improvements.
2026-07-18 23:27:05 +03:00
#ifdef __MQL4__
#property strict
#endif
#ifndef TIMEUTILS_UNIQUE_HEADER_ID_H
#define TIMEUTILS_UNIQUE_HEADER_ID_H
// First day of the week used by all week-related functions.
// Optionally, override the default before including this header:
//
// #define TIMEUTILS_FIRST_DAY_OF_WEEK SUNDAY
// #include "TimeUtils.mqh"
//
// Valid values: SUNDAY or MONDAY (default: MONDAY).
#ifndef TIMEUTILS_FIRST_DAY_OF_WEEK
#define TIMEUTILS_FIRST_DAY_OF_WEEK MONDAY
#endif
2026-07-21 21:05:41 +03:00
/*
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
Documentation & Core Capabilities
=================================
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
TimeUtils is a comprehensive date and time utility library for MQL5,
providing over 150 self-explanatory functions organized into logical
categories. It simplifies common calendar operations, eliminates
boilerplate datetime code, and correctly handles leap years, varying
month lengths, business days, and other calendar edge cases.
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
//####################################################################
//# #
//# Core Date/Time #
//# #
//####################################################################
Fast access to individual calendar fields together with lightweight
helpers for constructing and converting date/time values without
manually populating an MqlDateTime structure.
//====================================================================
// Calendar Fields
//====================================================================
Year(datetime) Month(datetime)
Day(datetime) Hour(datetime)
Minute(datetime) Second(datetime)
DayOfWeek(datetime) DateOnly(time)
DayOfYear(datetime) TimeOnly(time)
//####################################################################
//# #
//# Construction & Conversion #
//# #
//####################################################################
Create datetime values from calendar components or strings, and
efficiently convert between datetime and MqlDateTime structures.
//====================================================================
// Construction & Conversion
//====================================================================
DateFrom(2026, 7, 20)
DateFromString("2026.07.20 14:30")
TimeToStructFast(datetime, MqlDateTime)
StructToTimeFast(MqlDateTime)
//####################################################################
//# #
//# Calendar Indices & Positions #
//# #
//####################################################################
Retrieve absolute calendar indices or determine the position of a
timestamp within a year, quarter, month, week or day.
//====================================================================
// Absolute Indices
//====================================================================
YearIndex(datetime) MonthIndex(datetime)
QuarterIndex(datetime) WeekIndex(datetime)
DayIndex(datetime) HourIndex(datetime)
MinuteIndex(datetime)
//====================================================================
// Position Within Calendar
//====================================================================
Quarter(datetime)
WeekOfYear(datetime) WeekOfMonth(datetime)
HourOfYear(datetime) MinuteOfYear(datetime)
HourOfQuarter(datetime) MinuteOfQuarter(datetime)
HourOfMonth(datetime) MinuteOfMonth(datetime)
HourOfWeek(datetime) MinuteOfWeek(datetime)
MinuteOfDay(datetime)
SecsElapsedOfYear(datetime) SecsElapsedOfQuarter(datetime)
SecsElapsedOfMonth(datetime) SecsElapsedOfWeek(datetime)
SecsElapsedOfDay(datetime) SecsElapsedOfHour(datetime)
SecsElapsedOfMinute(datetime) SecsElapsedOfEpoch(datetime)
SecondsSinceMidnight(datetime)
//####################################################################
//# #
//# Navigation / Manipulation #
//# #
//####################################################################
Navigate through the calendar, snap timestamps to period boundaries,
replace individual date/time fields, round to common intervals, and
perform calendar-aware arithmetic.
//====================================================================
// Period Boundaries
//====================================================================
StartOfMinute(datetime) EndOfMinute(datetime)
StartOfHour(datetime) EndOfHour(datetime)
StartOfDay(datetime) EndOfDay(datetime)
StartOfWeek(datetime) EndOfWeek(datetime)
StartOfMonth(datetime) EndOfMonth(datetime)
StartOfQuarter(datetime) EndOfQuarter(datetime)
StartOfYear(datetime) EndOfYear(datetime)
StartOfToday() EndOfToday()
StartOfTomorrow() EndOfTomorrow()
StartOfYesterday() EndOfYesterday()
//====================================================================
// Calendar Navigation
//====================================================================
LastDayOfWeek(datetime) FirstWeekdayOfMonth(datetime, MONDAY)
LastDayOfMonth(datetime) LastWeekdayOfMonth(datetime, FRIDAY)
LastDayOfQuarter(datetime) NthWeekdayOfYearMonth(2026, 11, Nth, FRIDAY)
LastDayOfYear(datetime)
NextDayOfWeek(datetime, MONDAY) PreviousDayOfWeek(datetime, MONDAY)
NextOrSame(datetime, SUNDAY) PreviousOrSame(datetime, SUNDAY)
NextSunday(datetime) PreviousSunday(datetime)
NextMonday(datetime) PreviousMonday(datetime)
NextTuesday(datetime) PreviousTuesday(datetime)
NextWednesday(datetime) PreviousWednesday(datetime)
NextThursday(datetime) PreviousThursday(datetime)
NextFriday(datetime) PreviousFriday(datetime)
NextSaturday(datetime) PreviousSaturday(datetime)
//====================================================================
// Rounding & Alignment
//====================================================================
RoundToMinute(datetime) CeilToMinute(datetime)
RoundToHour(datetime) CeilToHour(datetime)
RoundToDay(datetime) CeilToDay(datetime)
RoundToWeek(datetime) CeilToWeek(datetime)
//====================================================================
// Field Replacement
//====================================================================
WithSecond(datetime, 30) WithMonth(datetime, 12)
WithMinute(datetime, 45) WithYear(datetime, 2030)
WithHour(datetime, 14) WithTime(datetime, 14, 30, 0)
WithDay(datetime, 15) WithDate(datetime, 2026, 7, 20)
WithDayOfWeek(datetime, FRIDAY)
//====================================================================
// Arithmetic
//====================================================================
AddSeconds(datetime, 30) SubSeconds(datetime, 30)
AddMinutes(datetime, 15) SubMinutes(datetime, 15)
AddHours(datetime, 8) SubHours(datetime, 8)
AddDays(datetime, 5) SubDays(datetime, 5)
AddBusinessDays(datetime, 5) SubBusinessDays(datetime, 5)
AddWeeks(datetime, 2) SubWeeks(datetime, 2)
AddMonths(datetime, 3) SubMonths(datetime, 3)
AddQuarters(datetime, 2) SubQuarters(datetime, 2)
AddYears(datetime, 10) SubYears(datetime, 10)
AddPeriod(datetime, MqlDateTime period)
SubPeriod(datetime, MqlDateTime period)
//####################################################################
//# #
//# Differences & Duration #
//# #
//####################################################################
Calculate exact elapsed time or calendar-aware differences between
two timestamps, including business days, calendar months and
human-readable calendar periods.
//====================================================================
// Exact Time Durations
//====================================================================
DifferenceInSeconds(from, to) DifferenceInBusinessDays(from, to)
DifferenceInMinutes(from, to) DifferenceInWeekendDays(from, to)
DifferenceInHours(from, to)
DifferenceInDays(from, to)
DifferenceInWeeks(from, to)
DifferenceInMonths(from, to)
DifferenceInQuarters(from, to)
DifferenceInYears(from, to)
//====================================================================
// Calendar Differences
//====================================================================
DifferenceInCalendarDays(from, to) DifferenceInCalendarWeeks(from, to)
DifferenceInCalendarMonths(from, to) DifferenceInCalendarQuarters(from, to)
DifferenceInCalendarYears(from, to)
CalendarDifference(from, to, MqlDateTime period)
CalendarDifferenceToString(from, to)
//####################################################################
//# #
//# Validation & Comparison #
//# #
//####################################################################
Convenience functions for validating dates, comparing timestamps,
and checking whether a date belongs to the current calendar period.
//====================================================================
// Day Checks
//====================================================================
IsWeekday(datetime) IsWeekend(datetime)
IsSunday(datetime) IsThursday(datetime)
IsMonday(datetime) IsFriday(datetime)
IsTuesday(datetime) IsSaturday(datetime)
IsWednesday(datetime)
IsFirstDayOfMonth(datetime) IsToday(datetime)
IsLastDayOfMonth(datetime) IsTomorrow(datetime)
IsYesterday(datetime)
//====================================================================
// Current Period
//====================================================================
IsCurrentMinute(datetime) IsCurrentMonth(datetime)
IsCurrentHour(datetime) IsCurrentQuarter(datetime)
IsCurrentWeek(datetime) IsCurrentYear(datetime)
//====================================================================
// Equality
//====================================================================
IsSameMinute(a, b) IsSameMonth(a, b)
IsSameHour(a, b) IsSameQuarter(a, b)
IsSameDay(a, b) IsSameYear(a, b)
IsSameWeek(a, b)
//####################################################################
//# #
//# Calendar Information #
//# #
//####################################################################
Query calendar properties such as month lengths, week counts and
leap years.
//====================================================================
// Calendar Information
//====================================================================
DaysInMonth(2026, 7) WeeksInMonth(2026, 7)
DaysInYear(2026) WeeksInYear(2026)
IsLeapYear(2028)
//####################################################################
//# #
//# Formatting & Display #
//# #
//####################################################################
2026-07-20 07:45:57 +03:00
2026-07-21 21:05:41 +03:00
Format dates and durations using built-in helpers or customizable
format strings for reports, logs and user interfaces.
//====================================================================
// Formatting
//====================================================================
string DayName(ENUM_DAY_OF_WEEK)
string MonthName(7)
string SecondsToString(3661)
string t2s(datetime, TIME_DATE | TIME_MINUTES)
string TimeFormat(datetime, "YYYY.MM.DD hh:mm")
//####################################################################
//# #
//# Trading Sessions #
//# #
//####################################################################
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
Utilities for recurring daily trading sessions, including the four
major FX sessions (Sydney, Tokyo, London and New York) as well as
user-defined sessions. Sessions may occur within a single day or span
midnight, and built-in FX sessions can be converted from UTC into
broker server time (or any other time zone) by supplying the
corresponding UTC offset, for example:
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
int offset = (int)(TimeTradeServer() - TimeGMT());
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
//====================================================================
// Generic Daily Sessions Major FX Sessions
//====================================================================
IsInSession(8,0,17,0) IsInMarketSession(SESSION_LONDON)
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
IsInSession(time, IsInMarketSession(time,
8,0,17,0) SESSION_LONDON,
utcOffsetSeconds)
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
IsInSession("08:00", CurrentMarketSession()
"17:00")
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
CurrentMarketSession(time,
utcOffsetSeconds)
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
MarketSessionName(CurrentMarketSession())
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
IsSessionOverlap(SESSION_LONDON,
SESSION_NEW_YORK)
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
IsSessionOverlap(time,
SESSION_LONDON,
SESSION_NEW_YORK,
utcOffsetSeconds)
2026-07-18 23:27:05 +03:00
2026-07-20 07:45:57 +03:00
2026-07-21 21:05:41 +03:00
//####################################################################
//# #
//# Economic Calendar / News #
//# #
//####################################################################
2026-07-20 07:45:57 +03:00
2026-07-21 21:05:41 +03:00
TimeUtils also provides lightweight helpers for working with the
MQL5 Economic Calendar, including news blackout detection and
countdowns to upcoming economic events.
2026-07-20 07:45:57 +03:00
2026-07-21 21:05:41 +03:00
//====================================================================
// News Checks Time Until News
//====================================================================
IsNearNews(checkTime, TimeUntilNews(from,
eventTime, events)
before,
after)
2026-07-20 07:45:57 +03:00
2026-07-21 21:05:41 +03:00
IsNearNews(checkTime, TimeUntilNews(from,
before, CALENDAR_IMPORTANCE_HIGH)
after,
CALENDAR_IMPORTANCE_HIGH)
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
*/
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| Time unit conversion constants |
//+------------------------------------------------------------------+
#define MINSECS 60ULL
#define HOURSECS 3600ULL
#define DAYSECS 86400ULL
#define WEEKSECS 604800ULL
#define DAYS_PER_4_YEARS 1461U // (4 * 365) + 1
#define DAYS_PER_400_YEARS 146097U // DAYS_PER_4_YEARS * 100 - 3 non-leap century years.
#define DAYS_TO_1970 719162 // Number of days from 1/1/0001 to 12/31/1969.
#define MARCH1_BASED_DOY 306 // Number of days between March 1 and January 1.
2026-07-20 07:45:57 +03:00
// Offset used to align calendar week boundaries.
// 1970-01-01 (Unix epoch) was a Thursday.
#define WEEK_OFFSET \
((THURSDAY - (int)TIMEUTILS_FIRST_DAY_OF_WEEK) * DAYSECS)
2026-07-18 23:27:05 +03:00
//####################################################################
//# #
2026-07-21 21:05:41 +03:00
//# Construction & Conversion #
2026-07-18 23:27:05 +03:00
//# #
//####################################################################
//+------------------------------------------------------------------+
//| Create a datetime value from the specified date and time. |
//+------------------------------------------------------------------+
datetime DateFrom(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 StructToTimeFast(dt);
}
//+------------------------------------------------------------------+
//| Create a datetime from a formatted date/time string. |
//+------------------------------------------------------------------+
datetime DateFromString(const string text)
{
return StringToTime(text);
}
//+------------------------------------------------------------------+
//| Faster alternative to MQL's 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 StructToTimeFast(const MqlDateTime& dt_struct)
{
const uint j = dt_struct.mon < 3;
const uint y = dt_struct.year - j;
const uint m = j ? dt_struct.mon + 12 : dt_struct.mon;
const uint f = (979 * m - 2918) / 32; // days before month
const uint n = dt_struct.day - 1 + f + 365*y + (y/4) - (y/100) + (y/400) - DAYS_TO_1970 - MARCH1_BASED_DOY;
return (datetime)((n * DAYSECS) + (dt_struct.hour * HOURSECS) + (dt_struct.min * MINSECS) + dt_struct.sec);
}
//+------------------------------------------------------------------+
//| Faster alternative to MQL's TimeToStruct() function. |
//| Converts a value of datetime type (number of seconds |
//| since 01.01.1970) into a structure variable MqlDateTime. |
//| https://github.com/cassioneri/eaf/blob/main/algorithms/neri_schneider.hpp
//+------------------------------------------------------------------+
bool TimeToStructFast(const datetime time, MqlDateTime& dt_struct)
{
uint n = (uint)(time / DAYSECS) ; // Unix day
uint N = n + 12699422 ; // Computational calendar day
uint a = 4 * N + 3 ; // N_1
uint c = a / DAYS_PER_400_YEARS ; // century
uint e = a % DAYS_PER_400_YEARS / 4 ; // [0, 36524] - dayOfCentury
uint b = 4 * e + 3 ; // N_2
uint z = b / DAYS_PER_4_YEARS ; // [0, 99] - yearOfCentury
uint h = b % DAYS_PER_4_YEARS / 4 ; // [0, 365] - Days since 1 March
uint d = 2141 * h + 197913 ; // N_3
uint M = d / 65536 ; // [3, 14] - Month
uint D = d % 65536 / 2141U ; // [0, 30] - Day
uint Y = 100 * c + z ; // Year
uint J = h >= MARCH1_BASED_DOY ; // JanFeb
uint l = z ? (z % 4 == 0) : (c % 4 == 0) ; // isLeap
uint seconds = (uint)(time - n * DAYSECS) ;
uint minutes = seconds / 60 ;
uint hours = minutes / 60 ;
dt_struct.year = (int)(Y - 32800 + J) ;
dt_struct.mon = (int)(J ? M - 12 : M) ;
dt_struct.day = (int)(D + 1) ;
dt_struct.hour = (int)(hours) ;
dt_struct.min = (int)(minutes - (hours * 60));
dt_struct.sec = (int)(seconds - (minutes * 60));
dt_struct.day_of_week = (int)((n + 4) % 7U);
dt_struct.day_of_year = (int)(h + (J ? -MARCH1_BASED_DOY : 59 + l));
return (true);
}
2026-07-21 21:05:41 +03:00
//####################################################################
//# #
//# Core Date/Time #
//# #
//####################################################################
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
//====================================================================
// Calendar Fields
//====================================================================
2026-07-18 23:27:05 +03:00
int Second(void) { return Second(TimeTradeServer()); } // gets current second (0..59)
int Minute(void) { return Minute(TimeTradeServer()); } // gets current minute (0..59)
int Hour(void) { return Hour(TimeTradeServer()); } // gets current hour (0..23)
int Day(void) { return Day(TimeTradeServer()); } // gets day of current month (1..31)
int Month(void) { return Month(TimeTradeServer()); } // gets current month (1..12)
int Year(void) { return Year(TimeTradeServer()); } // gets current year (1970..3000)
int DayOfWeek(void) { return DayOfWeek(TimeTradeServer()); } // gets day of current week (0..6)
int DayOfYear(void) { return DayOfYear(TimeTradeServer()); } // gets day of current year (0..365)
//+------------------------------------------------------------------+
//| Return seconds of minute as integer (0..59) |
//+------------------------------------------------------------------+
int Second(const datetime t)
{
return (int)(t % MINSECS);
}
//+------------------------------------------------------------------+
//| Return minutes of hour as integer (0..59) |
//+------------------------------------------------------------------+
int Minute(const datetime t)
{
return (int)((t / MINSECS) % MINSECS);
}
//+------------------------------------------------------------------+
//| Return hour of day as integer (0..23) |
//+------------------------------------------------------------------+
int Hour(const datetime t)
{
return (int)((t / HOURSECS) % 24U);
}
//+------------------------------------------------------------------+
//| Return day of month as integer (1..31) |
//+------------------------------------------------------------------+
int Day(const datetime t)
{
// MqlDateTime dt;
// TimeToStructFast(t, dt);
// return(dt.day);
uint dayOfCentury = ((((uint)(t / DAYSECS) + DAYS_TO_1970 + MARCH1_BASED_DOY) << 2) | 3U) % DAYS_PER_400_YEARS;
uint daySinceMarch1 = (dayOfCentury | 3U) % DAYS_PER_4_YEARS / 4;
uint monthDayPacked = daySinceMarch1 * 2141 + 197913;
return (int)((monthDayPacked & 0xFFFF) / 2141) + 1;
}
//+------------------------------------------------------------------+
//| Return the month number as integer (1..12) |
//+------------------------------------------------------------------+
int Month(const datetime t)
{
// MqlDateTime dt;
// TimeToStructFast(t, dt);
// return(dt.mon);
uint dayOfCentury = ((((uint)(t / DAYSECS) + DAYS_TO_1970 + MARCH1_BASED_DOY) << 2) | 3U) % DAYS_PER_400_YEARS;
uint daySinceMarch1 = (dayOfCentury | 3U) % DAYS_PER_4_YEARS / 4;
uint monthDayPacked = daySinceMarch1 * 2141 + 197913;
return (int)(monthDayPacked >> 16) - (daySinceMarch1 >= MARCH1_BASED_DOY ? 12 : 0);
}
//+------------------------------------------------------------------+
//| Return the year as integer (1970..3000) |
//+------------------------------------------------------------------+
int Year(const datetime t)
{
// MqlDateTime dt;
// TimeToStructFast(t, dt);
// return(dt.year);
uint days = ((((uint)(t / DAYSECS) + DAYS_TO_1970) << 2) | 3U);
uint century = days / DAYS_PER_400_YEARS;
uint year = ((days % DAYS_PER_400_YEARS) | 3U) / DAYS_PER_4_YEARS;
return (int)(100 * century + year) + 1;
}
//+------------------------------------------------------------------+
//| Day of the week as integer (0 = Sunday to 6 = Saturday) |
//+------------------------------------------------------------------+
int DayOfWeek(const datetime t)
{
return (int)((t / DAYSECS + THURSDAY) % 7U); // 1 Jan 1970 is Thursday
}
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
//| Returns the zero-based day of the year as integer (0...365) |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
int DayOfYear(const datetime t)
{
return (int)(((((((uint)(t / DAYSECS) + DAYS_TO_1970) << 2) | 3U) % DAYS_PER_400_YEARS) | 3U) % DAYS_PER_4_YEARS) >> 2;
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Return the date part for the given date. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
datetime DateOnly(const datetime t)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return StartOfDay(t);
}
//+------------------------------------------------------------------+
//| Return the time part for the given date. |
//+------------------------------------------------------------------+
datetime TimeOnly(const datetime t)
{
return (datetime)SecsElapsedOfDay(t);
2026-07-18 23:27:05 +03:00
}
2026-07-21 21:05:41 +03:00
//####################################################################
//# #
//# Calendar Indices & Positions #
//# #
//####################################################################
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
//====================================================================
// Absolute Indices
//====================================================================
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| Returns the zero-based minute index since 1970-01-01 00:00. |
//+------------------------------------------------------------------+
int MinuteIndex(const datetime t)
{
return (int)(t / MINSECS);
}
//+------------------------------------------------------------------+
//| Returns the zero-based hour index since 1970-01-01 00:00. |
//+------------------------------------------------------------------+
int HourIndex(const datetime t)
{
return (int)(t / HOURSECS);
}
//+------------------------------------------------------------------+
//| Returns the zero-based day index since 1970-01-01. |
//| Useful for indicators to determine 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);
}
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
//| Returns the zero-based calendar week index since the week |
//| containing 1970-01-01. |
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
int WeekIndex(const datetime t)
{
2026-07-20 07:45:57 +03:00
return (int)((t + WEEK_OFFSET) / WEEKSECS);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
//| Returns the zero-based calendar month index since 1970-01. |
//+------------------------------------------------------------------+
int MonthIndex(const datetime t)
{
return (Year(t) - 1970) * 12 + Month(t) - 1;
}
//+------------------------------------------------------------------+
//| Returns the zero-based calendar quarter index since 1970 Q1. |
//+------------------------------------------------------------------+
int QuarterIndex(const datetime t)
{
return (Year(t) - 1970) * 4 + Quarter(t) - 1;
}
//+------------------------------------------------------------------+
//| Returns the zero-based calendar year index since 1970. |
//+------------------------------------------------------------------+
int YearIndex(const datetime t)
{
return Year(t) - 1970;
}
2026-07-21 21:05:41 +03:00
//====================================================================
// Position Within Calendar
//====================================================================
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
//+------------------------------------------------------------------+
//| Return the year quarter number (1..4). |
//+------------------------------------------------------------------+
int Quarter(const datetime t)
{
return ((Month(t) - 1) / 3) + 1;
}
//+------------------------------------------------------------------+
//| Returns the calendar week number of the month (1...6). |
//| |
//| Week 1 is the first calendar week containing the first day of |
//| the month. The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
//+------------------------------------------------------------------+
int WeekOfMonth(const datetime t)
{
return WeekIndex(t) - WeekIndex(StartOfMonth(t)) + 1;
}
//+------------------------------------------------------------------+
//| Returns the calendar week number of the year (1...54). |
//| |
//| Week 1 is the first calendar week containing January 1st. |
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
//+------------------------------------------------------------------+
int WeekOfYear(const datetime t)
{
return WeekIndex(t) - WeekIndex(StartOfYear(t)) + 1;
}
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| Hours elapsed from the start of week for the given date. |
2026-07-20 07:45:57 +03:00
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
int HourOfWeek(const datetime t)
{
return (int)(SecsElapsedOfWeek(t) / HOURSECS);
}
//+------------------------------------------------------------------+
//| Hours elapsed from the start of month for the given date. |
//+------------------------------------------------------------------+
int HourOfMonth(const datetime t)
{
return (int)(SecsElapsedOfMonth(t) / HOURSECS);
}
//+------------------------------------------------------------------+
//| Hours elapsed from the start of quarter for the given date. |
//+------------------------------------------------------------------+
int HourOfQuarter(const datetime t)
{
return (int)(SecsElapsedOfQuarter(t) / HOURSECS);
}
//+------------------------------------------------------------------+
//| Hours elapsed from the start of year for the given date. |
//+------------------------------------------------------------------+
int HourOfYear(const datetime t)
{
return (int)(SecsElapsedOfYear(t) / HOURSECS);
}
//+------------------------------------------------------------------+
//| Minutes elapsed from the start of day for the given date. |
//+------------------------------------------------------------------+
int MinuteOfDay(const datetime t)
{
return (int)(SecsElapsedOfDay(t) / MINSECS);
}
//+------------------------------------------------------------------+
//| Minutes elapsed from the start of week for the given date. |
2026-07-20 07:45:57 +03:00
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
int MinuteOfWeek(const datetime t)
{
return (int)(SecsElapsedOfWeek(t) / MINSECS);
}
//+------------------------------------------------------------------+
//| Minutes elapsed from the start of month for the given date. |
//+------------------------------------------------------------------+
int MinuteOfMonth(const datetime t)
{
return (int)(SecsElapsedOfMonth(t) / MINSECS);
}
//+------------------------------------------------------------------+
//| Minutes elapsed from the start of quarter for the given date. |
//+------------------------------------------------------------------+
int MinuteOfQuarter(const datetime t)
{
return (int)(SecsElapsedOfQuarter(t) / MINSECS);
}
//+------------------------------------------------------------------+
//| Minutes elapsed from the start of year for the given date. |
//+------------------------------------------------------------------+
int MinuteOfYear(const datetime t)
{
return (int)(SecsElapsedOfYear(t) / MINSECS);
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of minute for the given date. |
//+------------------------------------------------------------------+
int SecsElapsedOfMinute(const datetime t)
{
return (int)(t % MINSECS);
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of hour for the given date. |
//+------------------------------------------------------------------+
int SecsElapsedOfHour(const datetime t)
{
return (int)(t % HOURSECS);
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of day for the given date. |
//+------------------------------------------------------------------+
int SecsElapsedOfDay(const datetime t)
{
return (int)(t % DAYSECS);
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of day for the given date. |
//+------------------------------------------------------------------+
int SecondsSinceMidnight(const datetime t)
{
return (int)(t % DAYSECS);
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of week for the given date. |
2026-07-20 07:45:57 +03:00
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
int SecsElapsedOfWeek(const datetime t)
{
2026-07-20 07:45:57 +03:00
return (int)((t + WEEK_OFFSET) % WEEKSECS);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
//| 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 quarter for the given date. |
//+------------------------------------------------------------------+
int SecsElapsedOfQuarter(const datetime t)
{
return (int)(t - StartOfQuarter(t));
}
//+------------------------------------------------------------------+
//| Seconds elapsed from the start of year for the given date. |
//+------------------------------------------------------------------+
int SecsElapsedOfYear(const datetime t)
{
return (int)(t - StartOfYear(t));
}
//+------------------------------------------------------------------+
//| Seconds elapsed since 1 Jan 1970 (Unix epoch) for the given date.|
//+------------------------------------------------------------------+
long SecsElapsedOfEpoch(const datetime t)
{
return (long)(t);
}
//####################################################################
//# #
2026-07-21 21:05:41 +03:00
//# Navigation / Manipulation #
2026-07-18 23:27:05 +03:00
//# #
//####################################################################
2026-07-21 21:05:41 +03:00
//====================================================================
// Period Boundaries
//====================================================================
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| 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);
}
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
//| Returns the start of the calendar week containing the given |
//| date/time. The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime StartOfWeek(const datetime t)
{
2026-07-20 07:45:57 +03:00
return t - ((t + WEEK_OFFSET) % WEEKSECS);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
//| Return the first day of a month for the given date. |
//+------------------------------------------------------------------+
datetime StartOfMonth(const datetime t)
{
const int y = Year(t);
const int m = Month(t);
return DateFrom(y, m, 1);
}
//+------------------------------------------------------------------+
//| Return the first day of a year quarter for the given date. |
//+------------------------------------------------------------------+
datetime StartOfQuarter(const datetime t)
{
const int y = Year(t);
const int m = Month(t);
const int qMonth = ((m - 1) / 3) * 3 + 1;
return DateFrom(y, qMonth, 1);
}
//+------------------------------------------------------------------+
//| Return the first day of a year for the given date. |
//+------------------------------------------------------------------+
datetime StartOfYear(const datetime t)
{
const int y = Year(t);
return DateFrom(y, 1, 1);
}
//+------------------------------------------------------------------+
//| Return the start second of today on the trade server. |
//+------------------------------------------------------------------+
datetime StartOfToday(void)
{
return StartOfDay(TimeTradeServer());
}
//+------------------------------------------------------------------+
//| Return the start second of tomorrow on the trade server. |
//+------------------------------------------------------------------+
datetime StartOfTomorrow(void)
{
return AddDays(StartOfDay(TimeTradeServer()), 1);
}
//+------------------------------------------------------------------+
//| Return the start second of yesterday on the trade server. |
//+------------------------------------------------------------------+
datetime StartOfYesterday(void)
{
return SubDays(StartOfDay(TimeTradeServer()), 1);
}
//+------------------------------------------------------------------+
//| 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. |
2026-07-20 07:45:57 +03:00
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime EndOfWeek(const datetime t)
{
return StartOfWeek(t) + (WEEKSECS - 1);
}
//+------------------------------------------------------------------+
//| Return the last second of a month for the given date. |
//+------------------------------------------------------------------+
datetime EndOfMonth(const datetime t)
{
// MqlDateTime dt;
// TimeToStructFast(t, dt);
// dt.day = DaysInMonth(dt.year, dt.mon);
// dt.hour = 23;
// dt.min = 59;
// dt.sec = 59;
// return(StructToTimeFast(dt));
2026-07-21 21:05:41 +03:00
return AddMonths(StartOfMonth(t), 1) - 1;
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
//| Return the last second of a year quarter for the given date. |
//+------------------------------------------------------------------+
datetime EndOfQuarter(const datetime t)
{
2026-07-21 21:05:41 +03:00
return AddMonths(StartOfQuarter(t), 3) - 1;
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
//| Return the last second of a year for the given date. |
//+------------------------------------------------------------------+
datetime EndOfYear(const datetime t)
{
2026-07-21 21:05:41 +03:00
return AddYears(StartOfYear(t), 1) - 1;
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
//| Return the last second of today on the trade server. |
//+------------------------------------------------------------------+
datetime EndOfToday(void)
{
return EndOfDay(TimeTradeServer());
}
//+------------------------------------------------------------------+
//| Return the last second of tomorrow on the trade server. |
//+------------------------------------------------------------------+
datetime EndOfTomorrow(void)
{
return AddDays(EndOfDay(TimeTradeServer()), 1);
}
//+------------------------------------------------------------------+
//| Return the last second of yesterday on the trade server. |
//+------------------------------------------------------------------+
datetime EndOfYesterday(void)
{
return SubDays(EndOfDay(TimeTradeServer()), 1);
}
2026-07-21 21:05:41 +03:00
//====================================================================
// Calendar Navigation
//====================================================================
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
//| Return the last day of a week for the given date. |
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime LastDayOfWeek(const datetime t)
{
return EndOfWeek(t) - (DAYSECS - 1);
}
//+------------------------------------------------------------------+
//| Return the last day of a month for the given date. |
//+------------------------------------------------------------------+
datetime LastDayOfMonth(const datetime t)
{
return EndOfMonth(t) - (DAYSECS - 1);
}
//+------------------------------------------------------------------+
//| Return the last day of a year quarter for the given date. |
//+------------------------------------------------------------------+
datetime LastDayOfQuarter(const datetime t)
{
return EndOfQuarter(t) - (DAYSECS - 1);
}
//+------------------------------------------------------------------+
//| Return the last day of a year for the given date. |
//+------------------------------------------------------------------+
datetime LastDayOfYear(const datetime t)
{
return EndOfYear(t) - (DAYSECS - 1);
}
//+==================================================================+
2026-07-21 21:05:41 +03:00
//| Nth() Weekday |
2026-07-18 23:27:05 +03:00
//+==================================================================+
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Return the first weekday of the month. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
datetime FirstWeekdayOfMonth(const datetime t,
const ENUM_DAY_OF_WEEK weekday = SUNDAY)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return NthWeekdayOfYearMonth(Year(t), Month(t), 1, weekday);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Return the last weekday of the month. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
datetime LastWeekdayOfMonth(const datetime t,
const ENUM_DAY_OF_WEEK weekday = SUNDAY)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return NthWeekdayOfYearMonth(Year(t),Month(t),-1,weekday);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Return the Nth weekday of the given year and month. |
//| |
//| Nth > 0 : 1 = first, 2 = second, ... |
//| Nth < 0 : -1 = last, -2 = second last, ... |
//| Returns 0 if the requested occurrence does not exist. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
datetime NthWeekdayOfYearMonth(const int year,
const int month,
const int Nth,
const ENUM_DAY_OF_WEEK weekday = SUNDAY)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
if(Nth == 0 || month < 1 || month > 12)
return 0;
const datetime first = DateFrom(year, month, 1);
const datetime last = DateFrom(year, month, DaysInMonth(year, month));
int jumpdays = (MathAbs(Nth) - 1) * 7;
if(Nth > 0)
{
// Count from the beginning of the month.
jumpdays += (7 + weekday - DayOfWeek(first)) % 7;
datetime result = AddDays(first, jumpdays);
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
return (result <= last) ? result : 0;
}
else
{
// Count from the end of the month.
jumpdays += (7 - weekday + DayOfWeek(last)) % 7;
datetime result = SubDays(last, jumpdays);
return (result >= first) ? result : 0;
}
}
2026-07-18 23:27:05 +03:00
//+==================================================================+
2026-07-21 21:05:41 +03:00
//| Next() Weekday |
2026-07-18 23:27:05 +03:00
//+==================================================================+
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Return the next occurrence of the specified weekday after the |
//| given date. The returned value is the start of that day. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
datetime NextDayOfWeek(const datetime t,
const ENUM_DAY_OF_WEEK weekday = SUNDAY)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
const datetime day = StartOfDay(t);
int delta = weekday - DayOfWeek(t);
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
// Normalize to the next occurrence (strictly after).
if(delta <= 0)
delta += 7;
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
return AddDays(day, delta);
}
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Return the next occurrence of the specified weekday on or after |
//| the given date. The returned value is the start of that day. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
datetime NextOrSame(const datetime t,
const ENUM_DAY_OF_WEEK weekday = SUNDAY)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
const datetime day = StartOfDay(t);
2026-07-18 23:27:05 +03:00
int delta = weekday - DayOfWeek(t);
2026-07-21 21:05:41 +03:00
// Normalize to the next occurrence (including today).
if(delta < 0)
delta += 7;
return AddDays(day, delta);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
//| When is the next Sunday? |
//+------------------------------------------------------------------+
datetime NextSunday(const datetime t)
{
return NextDayOfWeek(t, SUNDAY);
}
//+------------------------------------------------------------------+
//| When is the next Monday? |
//+------------------------------------------------------------------+
datetime NextMonday(const datetime t)
{
return NextDayOfWeek(t, MONDAY);
}
//+------------------------------------------------------------------+
//| When is the next Tuesday? |
//+------------------------------------------------------------------+
datetime NextTuesday(const datetime t)
{
return NextDayOfWeek(t, TUESDAY);
}
//+------------------------------------------------------------------+
//| When is the next Wednesday? |
//+------------------------------------------------------------------+
datetime NextWednesday(const datetime t)
{
return NextDayOfWeek(t, WEDNESDAY);
}
//+------------------------------------------------------------------+
//| When is the next Thursday? |
//+------------------------------------------------------------------+
datetime NextThursday(const datetime t)
{
return NextDayOfWeek(t, THURSDAY);
}
//+------------------------------------------------------------------+
//| When is the next Friday? |
//+------------------------------------------------------------------+
datetime NextFriday(const datetime t)
{
return NextDayOfWeek(t, FRIDAY);
}
//+------------------------------------------------------------------+
//| When is the next Saturday? |
//+------------------------------------------------------------------+
datetime NextSaturday(const datetime t)
{
return NextDayOfWeek(t, SATURDAY);
}
//+==================================================================+
//| Previous() Weekday |
//+==================================================================+
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Return the previous occurrence of the specified weekday before |
//| the given date. The returned value is the start of that day. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
datetime PreviousDayOfWeek(const datetime t,
const ENUM_DAY_OF_WEEK weekday = SUNDAY)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
const datetime day = StartOfDay(t);
int delta = weekday - DayOfWeek(t);
// Normalize to the previous occurrence (strictly before).
if(delta >= 0)
delta -= 7;
return AddDays(day, delta);
}
//+------------------------------------------------------------------+
//| Return the previous occurrence of the specified weekday on or |
//| before the given date. The returned value is the start of that |
//| day. |
//+------------------------------------------------------------------+
datetime PreviousOrSame(const datetime t,
const ENUM_DAY_OF_WEEK weekday = SUNDAY)
{
const datetime day = StartOfDay(t);
int delta = weekday - DayOfWeek(t);
// Normalize to the previous occurrence (including today).
if(delta > 0)
delta -= 7;
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
return AddDays(day, delta);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
//| When is the previous Sunday? |
//+------------------------------------------------------------------+
datetime PreviousSunday(const datetime t)
{
return PreviousDayOfWeek(t, SUNDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Monday? |
//+------------------------------------------------------------------+
datetime PreviousMonday(const datetime t)
{
return PreviousDayOfWeek(t, MONDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Tuesday? |
//+------------------------------------------------------------------+
datetime PreviousTuesday(const datetime t)
{
return PreviousDayOfWeek(t, TUESDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Wednesday? |
//+------------------------------------------------------------------+
datetime PreviousWednesday(const datetime t)
{
return PreviousDayOfWeek(t, WEDNESDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Thursday? |
//+------------------------------------------------------------------+
datetime PreviousThursday(const datetime t)
{
return PreviousDayOfWeek(t, THURSDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Friday? |
//+------------------------------------------------------------------+
datetime PreviousFriday(const datetime t)
{
return PreviousDayOfWeek(t, FRIDAY);
}
//+------------------------------------------------------------------+
//| When is the previous Saturday? |
//+------------------------------------------------------------------+
datetime PreviousSaturday(const datetime t)
{
return PreviousDayOfWeek(t, SATURDAY);
}
2026-07-21 21:05:41 +03:00
//====================================================================
// Rounding & Alignment
//====================================================================
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Rounds halfway the given date to the nearest minute. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
datetime RoundToMinute(const datetime t)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return StartOfMinute(t + MINSECS / 2);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Rounds halfway the given date to the nearest hour. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
datetime RoundToHour(const datetime t)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return StartOfHour(t + HOURSECS / 2);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Rounds halfway the given date to the nearest day. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
datetime RoundToDay(const datetime t)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return StartOfDay(t + DAYSECS / 2);
}
//+------------------------------------------------------------------+
//| Rounds halfway the given date to the nearest week. |
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
//+------------------------------------------------------------------+
datetime RoundToWeek(const datetime t)
{
return StartOfWeek(t + WEEKSECS / 2);
2026-07-18 23:27:05 +03:00
}
2026-07-21 21:05:41 +03:00
//+------------------------------------------------------------------+
//| 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. |
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
//+------------------------------------------------------------------+
datetime CeilToWeek(const datetime t)
{
return StartOfWeek(t + WEEKSECS - 1);
}
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
//====================================================================
// Field Replacement
//====================================================================
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| Returns a copy of the given datetime with the second updated. |
2026-08-10 15:28:29 +03:00
//| Returns -1 if second is outside 0..59. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime WithSecond(const datetime t, const int second)
{
if(second < 0 || second > 59)
return -1;
return AddSeconds(t, second - Second(t));
}
//+------------------------------------------------------------------+
//| Returns a copy of the given datetime with the minute updated. |
2026-08-10 15:28:29 +03:00
//| Returns -1 if minute is outside 0..59. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime WithMinute(const datetime t, const int minute)
{
if(minute < 0 || minute > 59)
return -1;
return AddMinutes(t, minute - Minute(t));
}
//+------------------------------------------------------------------+
//| Returns a copy of the given datetime with the hour updated. |
2026-08-10 15:28:29 +03:00
//| Returns -1 if hour is outside 0..23. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime WithHour(const datetime t, const int hour)
{
if(hour < 0 || hour > 23)
return -1;
return AddHours(t, hour - Hour(t));
}
//+------------------------------------------------------------------+
2026-08-10 15:28:29 +03:00
//| Returns a copy of the given datetime with the day of month |
//| updated. Returns -1 if day is outside 1..DaysInMonth(t's year, |
//| t's month). |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime WithDay(const datetime t, const int day)
{
if(day < 1 || day > DaysInMonth(Year(t), Month(t)))
return -1;
return AddDays(t, day - Day(t));
}
//+------------------------------------------------------------------+
//| Returns a copy of the given datetime with the month updated. |
2026-08-10 15:28:29 +03:00
//| Returns -1 if month is outside 1..12. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime WithMonth(const datetime t, const int month)
{
if(month < 1 || month > 12)
return -1;
return AddMonths(t, month - Month(t));
}
//+------------------------------------------------------------------+
//| Returns a copy of the given datetime with the year updated. |
2026-08-10 15:28:29 +03:00
//| Returns -1 if year is outside 1970..3000. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime WithYear(const datetime t, const int year)
{
if(year < 1970 || year > 3000)
return -1;
return AddYears(t, year - Year(t));
}
//+------------------------------------------------------------------+
//| Returns a copy of the given datetime adjusted to the specified |
//| weekday within the current week, preserving the time of day. |
2026-07-20 07:45:57 +03:00
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
datetime WithDayOfWeek(const datetime t,
const ENUM_DAY_OF_WEEK weekday)
2026-07-18 23:27:05 +03:00
{
2026-07-20 07:45:57 +03:00
const int first = (int)TIMEUTILS_FIRST_DAY_OF_WEEK;
const int current = DayOfWeek(t);
int delta = (int)weekday - current;
2026-07-18 23:27:05 +03:00
2026-07-20 07:45:57 +03:00
if((int)weekday < first)
delta += 7;
2026-07-18 23:27:05 +03:00
2026-07-20 07:45:57 +03:00
if(current < first)
delta -= 7;
2026-07-18 23:27:05 +03:00
2026-07-20 07:45:57 +03:00
return AddDays(t, delta);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
//| Returns a copy of the given datetime with the specified time, |
2026-08-10 15:28:29 +03:00
//| preserving the date (i.e., replace time). Returns -1 if hour, |
//| minute, or second is out of range. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime WithTime(const datetime t,
const int hour,
const int minute,
const int second)
{
if(hour < 0 || hour > 23 ||
minute < 0 || minute > 59 ||
second < 0 || second > 59)
return -1;
datetime res = t;
res = WithHour(res, hour);
res = WithMinute(res, minute);
return WithSecond(res, second);
}
//+------------------------------------------------------------------+
//| Returns a copy of the given datetime with the specified date, |
2026-08-10 15:28:29 +03:00
//| preserving the time of day (i.e., replace date). Returns -1 if |
//| year, month, or day is out of range (including day not existing |
//| in the given year/month, e.g. February 30). |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
datetime WithDate(const datetime t,
const int year,
const int month,
const int day)
{
MqlDateTime dt;
TimeToStructFast(t, dt);
if(year < 1970 || year > 3000 ||
month < 1 || month > 12 ||
day < 1 || day > DaysInMonth(year, month))
return -1;
dt.year = year;
dt.mon = month;
dt.day = day;
return StructToTimeFast(dt);
}
2026-07-21 21:05:41 +03:00
//====================================================================
// Arithmetic
//====================================================================
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| 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 + ((datetime)amount * MINSECS);
}
//+------------------------------------------------------------------+
//| Add the specified number of hours to the given date. |
//+------------------------------------------------------------------+
datetime AddHours(const datetime t, const int amount)
{
return t + ((datetime)amount * HOURSECS);
}
//+------------------------------------------------------------------+
//| Add the specified number of days to the given date. |
//+------------------------------------------------------------------+
datetime AddDays(const datetime t, const int amount)
{
return t + ((datetime)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)
{
2026-08-10 15:28:29 +03:00
int stepDays = amount < 0 ? -1 : 1;
2026-07-18 23:27:05 +03:00
int fullWeeks = amount / 5;
int remaining = MathAbs(amount) % 5;
datetime t_end = AddDays(t, fullWeeks * 7);
// Loop over remaining business days
while(remaining > 0)
{
2026-08-10 15:28:29 +03:00
t_end = AddDays(t_end, stepDays);
2026-07-18 23:27:05 +03:00
if(IsWeekday(t_end))
{
remaining--;
}
}
// If we add amount and land on a weekend, we add/reduce days
// to land on the next business day.
if(amount != 0)
{
if(IsSaturday(t_end))
2026-08-10 15:28:29 +03:00
t_end = AddDays(t_end, (stepDays < 0 ? 2 : -1));
2026-07-18 23:27:05 +03:00
else if(IsSunday(t_end))
2026-08-10 15:28:29 +03:00
t_end = AddDays(t_end, (stepDays < 0 ? 1 : -2));
2026-07-18 23:27:05 +03:00
}
return t_end;
}
//+------------------------------------------------------------------+
//| Add the specified number of weeks to the given date. |
//+------------------------------------------------------------------+
datetime AddWeeks(const datetime t, const int amount)
{
return t + ((datetime)amount * WEEKSECS);
}
//+------------------------------------------------------------------+
//| Add the specified number of months to the given date. |
//+------------------------------------------------------------------+
datetime AddMonths(const datetime t, const int amount)
{
MqlDateTime dt;
TimeToStructFast(t, dt);
int totalMonths = dt.year * 12 + (dt.mon - 1) + amount; // month is 1-based
dt.year = totalMonths / 12;
dt.mon = (totalMonths % 12) + 1;
dt.day = MathMin(dt.day, DaysInMonth(dt.year, dt.mon));
return StructToTimeFast(dt);
}
//+------------------------------------------------------------------+
//| Add the specified number of year quarters to the given date. |
//+------------------------------------------------------------------+
datetime AddQuarters(const datetime t, const int amount)
{
return AddMonths(t, amount * 3);
}
//+------------------------------------------------------------------+
//| Add the specified number of years to the given date. |
//+------------------------------------------------------------------+
datetime AddYears(const datetime t, const int amount)
{
return AddMonths(t, amount * 12);
}
//+------------------------------------------------------------------+
//| Returns a copy of the given datetime with the specified |
//| calendar period added. The period is expressed in calendar |
//| years, months, days, hours, minutes, and seconds. |
//| |
2026-08-10 15:28:29 +03:00
//| calendarPeriod reuses the MqlDateTime struct as a DURATION, not |
//| an absolute date/time: e.g. mon is a count of months (0..11), |
//| not a calendar month number (1..12), and day/hour/min/sec are |
//| likewise counts, not calendar positions. This matches the |
//| struct filled in by CalendarDifference(). |
//| |
2026-07-18 23:27:05 +03:00
//| For periods returned by CalendarDifference(), |
//| AddPeriod(from, period) reconstructs the original end date. |
2026-08-10 15:28:29 +03:00
//| |
//| Returns -1 if any field of calendarPeriod is negative or out of |
//| its documented range (mon > 11, hour > 23, min > 59, sec > 59). |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
datetime AddPeriod(const datetime t,
const MqlDateTime& calendarPeriod)
2026-07-18 23:27:05 +03:00
{
if(calendarPeriod.year < 0)
return -1;
if(calendarPeriod.mon < 0 || calendarPeriod.mon > 11)
return -1;
if(calendarPeriod.day < 0)
return -1;
if(calendarPeriod.hour < 0 || calendarPeriod.hour > 23)
return -1;
if(calendarPeriod.min < 0 || calendarPeriod.min > 59)
return -1;
if(calendarPeriod.sec < 0 || calendarPeriod.sec > 59)
return -1;
datetime res = t;
res = AddMonths(res, calendarPeriod.year * 12 + calendarPeriod.mon);
res = AddDays(res, calendarPeriod.day);
res = AddHours(res, calendarPeriod.hour);
res = AddMinutes(res, calendarPeriod.min);
res = AddSeconds(res, calendarPeriod.sec);
return res;
}
//+------------------------------------------------------------------+
//| 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 quarters from the given date. |
//+------------------------------------------------------------------+
datetime SubQuarters(const datetime t, const int amount)
{
return AddQuarters(t, -amount);
}
//+------------------------------------------------------------------+
//| Subtract the specified number of years from the given date. |
//+------------------------------------------------------------------+
datetime SubYears(const datetime t, const int amount)
{
return AddYears(t, -amount);
}
//+------------------------------------------------------------------+
//| Returns a copy of the given datetime with the specified |
//| calendar period subtracted. The period is expressed in calendar |
//| years, months, days, hours, minutes, and seconds. |
//| |
2026-08-10 15:28:29 +03:00
//| calendarPeriod reuses the MqlDateTime struct as a DURATION, not |
//| an absolute date/time - see AddPeriod() for details. |
//| |
2026-07-18 23:27:05 +03:00
//| This function performs the inverse calendar operation of |
//| AddPeriod(), applying the period in reverse order. |
//| |
//| Note that calendar arithmetic is generally not invertible due |
//| to month-end clamping and varying month lengths. Therefore, for |
//| periods returned by CalendarDifference(), |
//| |
//| AddPeriod(from, period) == to |
//| |
//| is guaranteed, but |
//| |
//| SubPeriod(to, period) == from |
//| |
//| is not guaranteed in all cases. |
2026-08-10 15:28:29 +03:00
//| |
//| Returns -1 if any field of calendarPeriod is negative or out of |
//| its documented range (mon > 11, hour > 23, min > 59, sec > 59). |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
datetime SubPeriod(const datetime t,
const MqlDateTime& calendarPeriod)
2026-07-18 23:27:05 +03:00
{
if(calendarPeriod.year < 0)
return -1;
if(calendarPeriod.mon < 0 || calendarPeriod.mon > 11)
return -1;
if(calendarPeriod.day < 0)
return -1;
if(calendarPeriod.hour < 0 || calendarPeriod.hour > 23)
return -1;
if(calendarPeriod.min < 0 || calendarPeriod.min > 59)
return -1;
if(calendarPeriod.sec < 0 || calendarPeriod.sec > 59)
return -1;
datetime res = t;
res = AddSeconds(res, -calendarPeriod.sec);
res = AddMinutes(res, -calendarPeriod.min);
res = AddHours(res, -calendarPeriod.hour);
res = AddDays(res, -calendarPeriod.day);
res = AddMonths(res, -(calendarPeriod.year * 12 + calendarPeriod.mon));
return res;
}
//####################################################################
//# #
2026-07-21 21:05:41 +03:00
//# Differences & Duration #
2026-07-18 23:27:05 +03:00
//# #
//####################################################################
2026-07-21 21:05:41 +03:00
//====================================================================
// Exact Time Durations
//====================================================================
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| Return the number of elapsed seconds between two dates. |
//+------------------------------------------------------------------+
long DifferenceInSeconds(const datetime from, const datetime to)
{
return (long)(to - from);
}
//+------------------------------------------------------------------+
//| Return the number of elapsed minutes between two dates. |
//+------------------------------------------------------------------+
int DifferenceInMinutes(const datetime from, const datetime to)
{
return (int)((to - from) / (int)MINSECS);
}
//+------------------------------------------------------------------+
//| Return the number of elapsed hours between two dates. |
//+------------------------------------------------------------------+
int DifferenceInHours(const datetime from, const datetime to)
{
return (int)((to - from) / (int)HOURSECS);
}
//+------------------------------------------------------------------+
//| Return the number of elapsed 24-hour periods between two dates. |
//+------------------------------------------------------------------+
int DifferenceInDays(const datetime from, const datetime to)
{
return (int)((to - from) / (int)DAYSECS);
}
//+------------------------------------------------------------------+
//| Return the number of elapsed full weeks between two dates. |
//+------------------------------------------------------------------+
int DifferenceInWeeks(const datetime from, const datetime to)
{
return (int)((to - from) / (int)WEEKSECS);
}
//+------------------------------------------------------------------+
//| Return the number of elapsed full months between two dates. |
//+------------------------------------------------------------------+
int DifferenceInMonths(const datetime from, const datetime to)
{
if(from > to)
return -DifferenceInMonths(to, from);
int months = DifferenceInCalendarMonths(from, to);
// https://github.com/dateutil/dateutil/blob/master/src/dateutil/relativedelta.py#L153
// add months back. If we've overshot our target, make an adjustment
return AddMonths(from, months) <= to ? months : months - 1;
}
//+------------------------------------------------------------------+
//| Return the number of elapsed full quarters between dates. |
//+------------------------------------------------------------------+
int DifferenceInQuarters(const datetime from, const datetime to)
{
return DifferenceInMonths(from, to) / 3;
}
//+------------------------------------------------------------------+
//| Return the number of elapsed full years between two dates. |
//+------------------------------------------------------------------+
int DifferenceInYears(const datetime from, const datetime to)
{
return DifferenceInMonths(from, to) / 12;
}
//+------------------------------------------------------------------+
//| Return the number of business days (Mon-Fri) in the half-open |
2026-08-10 15:28:29 +03:00
//| interval [from, to), excluding weekends. If to < from, returns |
//| the negative of the business days in [to, from). |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
int DifferenceInBusinessDays(const datetime from, const datetime to)
{
2026-08-10 15:28:29 +03:00
const datetime start = MathMin(from, to);
const datetime end = MathMax(from, to);
2026-07-18 23:27:05 +03:00
2026-08-10 15:28:29 +03:00
const int totalDays = DifferenceInCalendarDays(start, end); // always > 0 here
const int fullWeeks = totalDays / 7;
const int remaining = totalDays % 7;
2026-07-18 23:27:05 +03:00
2026-08-10 15:28:29 +03:00
int business = fullWeeks * 5;
2026-07-18 23:27:05 +03:00
2026-08-10 15:28:29 +03:00
datetime dt_temp = start;
2026-07-18 23:27:05 +03:00
// Loop over remaining days not part of a full week
for(int i = 0; i < remaining; i++)
{
if(IsWeekday(dt_temp))
{
2026-08-10 15:28:29 +03:00
business++;
2026-07-18 23:27:05 +03:00
}
2026-08-10 15:28:29 +03:00
dt_temp = AddDays(dt_temp, 1);
2026-07-18 23:27:05 +03:00
}
2026-08-10 15:28:29 +03:00
return (from <= to) ? business : -business;
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
//| Return the number of weekend days in the half-open interval |
//| [from, to). The end date is not included. |
//+------------------------------------------------------------------+
int DifferenceInWeekendDays(const datetime from, const datetime to)
{
return DifferenceInCalendarDays(from, to)
- DifferenceInBusinessDays(from, to);
}
2026-07-21 21:05:41 +03:00
//====================================================================
// Calendar Differences
//====================================================================
//+------------------------------------------------------------------+
//| Returns the difference in the calendar day numbers between two |
//| date/time values, ignoring the time-of-day components. |
//+------------------------------------------------------------------+
int DifferenceInCalendarDays(const datetime from, const datetime to)
{
return DayIndex(to) - DayIndex(from);
}
//+------------------------------------------------------------------+
//| Returns the difference between the calendar week indices of |
//| two date/time values, ignoring the time-of-day components. |
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
//+------------------------------------------------------------------+
int DifferenceInCalendarWeeks(const datetime from, const datetime to)
{
return WeekIndex(to) - WeekIndex(from);
}
//+------------------------------------------------------------------+
//| Returns the difference in the calendar month numbers between |
//| two dates, ignoring the day and time components. |
//+------------------------------------------------------------------+
int DifferenceInCalendarMonths(const datetime from, const datetime to)
{
return MonthIndex(to) - MonthIndex(from);
}
//+------------------------------------------------------------------+
//| Returns the difference in the calendar quarter numbers between |
//| two dates, ignoring the month, day, and time components. |
//+------------------------------------------------------------------+
int DifferenceInCalendarQuarters(const datetime from, const datetime to)
{
return QuarterIndex(to) - QuarterIndex(from);
}
//+------------------------------------------------------------------+
//| Returns the difference in the calendar year numbers between |
//| two dates, ignoring the month, day, and time components. |
//+------------------------------------------------------------------+
int DifferenceInCalendarYears(const datetime from, const datetime to)
{
return YearIndex(to) - YearIndex(from);
}
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| Returns the calendar difference between two dates, broken down |
//| into years, months, days, hours, minutes, and seconds. |
2026-08-10 15:28:29 +03:00
//| |
//| diff reuses the MqlDateTime struct as a DURATION, |
//| not an absolute date/time - see AddPeriod() for details. |
//| |
//| The breakdown is always non-negative - from and to are swapped |
//| internally if needed, so the order of arguments does not affect |
//| the result. |
//| |
//| For periods returned by CalendarDifference(), |
//| AddPeriod(from, period) reconstructs the original end date. |
//| |
//| Note that calendar arithmetic is generally not invertible due |
//| to month-end clamping and varying month lengths - see |
//| SubPeriod() for details. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-08-10 15:28:29 +03:00
bool CalendarDifference(const datetime from,
const datetime to,
MqlDateTime& diff)
2026-07-18 23:27:05 +03:00
{
const static MqlDateTime zero = {};
2026-07-20 07:45:57 +03:00
diff = zero;
2026-07-18 23:27:05 +03:00
if(from == to)
return(true);
2026-08-10 15:28:29 +03:00
datetime start = MathMin(from, to);
datetime end = MathMax(from, to);
2026-07-18 23:27:05 +03:00
2026-08-10 15:28:29 +03:00
const int totalMonths =
DifferenceInMonths(start, end);
2026-07-18 23:27:05 +03:00
diff.year = totalMonths / 12;
diff.mon = totalMonths % 12;
2026-08-10 15:28:29 +03:00
start = AddMonths(start, totalMonths);
2026-07-18 23:27:05 +03:00
2026-08-10 15:28:29 +03:00
diff.day = DifferenceInDays(start, end);
start = AddDays(start, diff.day);
2026-07-18 23:27:05 +03:00
2026-08-10 15:28:29 +03:00
diff.hour = DifferenceInHours(start, end);
start = AddHours(start, diff.hour);
2026-07-18 23:27:05 +03:00
2026-08-10 15:28:29 +03:00
diff.min = DifferenceInMinutes(start, end);
start = AddMinutes(start, diff.min);
2026-07-18 23:27:05 +03:00
2026-08-10 15:28:29 +03:00
diff.sec = (int)DifferenceInSeconds(start, end);
2026-07-18 23:27:05 +03:00
return (true);
}
//+------------------------------------------------------------------+
//| Returns the calendar difference between two dates as a |
//| human-readable string (e.g. "2y 3m 5d 04:12:30"). |
//+------------------------------------------------------------------+
string CalendarDifferenceToString(const datetime from, const datetime to)
{
if(from == to)
return "0y 0m 0d 00:00:00";
MqlDateTime diff;
CalendarDifference(from, to, diff);
string result = "";
result += IntegerToString(diff.year);
result += "y " + IntegerToString(diff.mon);
result += "m " + IntegerToString(diff.day);
result += "d " + IntegerToString(diff.hour, 2, '0');
result += ":" + IntegerToString(diff.min, 2, '0');
result += ":" + IntegerToString(diff.sec, 2, '0');
return result;
}
//####################################################################
//# #
2026-07-21 21:05:41 +03:00
//# Validation & Comparison #
2026-07-18 23:27:05 +03:00
//# #
//####################################################################
2026-07-21 21:05:41 +03:00
//====================================================================
// Day Checks
//====================================================================
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| Is the given date the first day of a month? |
//+------------------------------------------------------------------+
bool IsFirstDayOfMonth(const datetime t)
{
return Day(t) == 1;
}
//+------------------------------------------------------------------+
//| Is the given date the last day of a month? |
//+------------------------------------------------------------------+
bool IsLastDayOfMonth(const datetime t)
{
return EndOfDay(t) == EndOfMonth(t);
}
//+------------------------------------------------------------------+
//| Does the given date fall on a weekend? |
//+------------------------------------------------------------------+
bool IsWeekend(const datetime t)
{
int dow = DayOfWeek(t);
return dow == SATURDAY || dow == SUNDAY;
}
//+------------------------------------------------------------------+
//| Does the given date fall on a business day? |
//+------------------------------------------------------------------+
bool IsWeekday(const datetime t)
{
return !IsWeekend(t);
}
//+------------------------------------------------------------------+
//| Is the given date Sunday? |
//+------------------------------------------------------------------+
bool IsSunday(const datetime t)
{
return DayOfWeek(t) == SUNDAY;
}
//+------------------------------------------------------------------+
//| Is the given date Monday? |
//+------------------------------------------------------------------+
bool IsMonday(const datetime t)
{
return DayOfWeek(t) == MONDAY;
}
//+------------------------------------------------------------------+
//| Is the given date Tuesday? |
//+------------------------------------------------------------------+
bool IsTuesday(const datetime t)
{
return DayOfWeek(t) == TUESDAY;
}
//+------------------------------------------------------------------+
//| Is the given date Wednesday? |
//+------------------------------------------------------------------+
bool IsWednesday(const datetime t)
{
return DayOfWeek(t) == WEDNESDAY;
}
//+------------------------------------------------------------------+
//| Is the given date Thursday? |
//+------------------------------------------------------------------+
bool IsThursday(const datetime t)
{
return DayOfWeek(t) == THURSDAY;
}
//+------------------------------------------------------------------+
//| Is the given date Friday? |
//+------------------------------------------------------------------+
bool IsFriday(const datetime t)
{
return DayOfWeek(t) == FRIDAY;
}
//+------------------------------------------------------------------+
//| Is the given date Saturday? |
//+------------------------------------------------------------------+
bool IsSaturday(const datetime t)
{
return DayOfWeek(t) == SATURDAY;
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Is the given date today on the trade server |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
bool IsToday(const datetime t)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return IsSameDay(t, TimeTradeServer());
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Is the given date tomorrow on the trade server |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
bool IsTomorrow(const datetime t)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return IsSameDay(t, AddDays(TimeTradeServer(), 1));
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Is the given date yesterday on the trade server |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
bool IsYesterday(const datetime t)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return IsSameDay(t, SubDays(TimeTradeServer(), 1));
2026-07-18 23:27:05 +03:00
}
2026-07-21 21:05:41 +03:00
//====================================================================
// Current Period
//====================================================================
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| Is the given date in the same minute as the current server time |
//+------------------------------------------------------------------+
bool IsCurrentMinute(const datetime t)
{
return IsSameMinute(t, TimeTradeServer());
}
//+------------------------------------------------------------------+
//| Is the given date in the same hour as the current server time |
//+------------------------------------------------------------------+
bool IsCurrentHour(const datetime t)
{
return IsSameHour(t, TimeTradeServer());
}
//+------------------------------------------------------------------+
//| Is the given date in the same week as the current server time |
2026-07-20 07:45:57 +03:00
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
bool IsCurrentWeek(const datetime t)
{
return IsSameWeek(t, TimeTradeServer());
}
//+------------------------------------------------------------------+
//| Is the given date in the same month as the current server time |
//+------------------------------------------------------------------+
bool IsCurrentMonth(const datetime t)
{
return IsSameMonth(t, TimeTradeServer());
}
//+------------------------------------------------------------------+
//| Is this date in the same quarter (and year) as the server ? |
//+------------------------------------------------------------------+
bool IsCurrentQuarter(const datetime t)
{
return IsSameQuarter(t, TimeTradeServer());
}
//+------------------------------------------------------------------+
//| Is the given date in the same year as the current server time |
//+------------------------------------------------------------------+
bool IsCurrentYear(const datetime t)
{
return IsSameYear(t, TimeTradeServer());
}
2026-07-21 21:05:41 +03:00
//====================================================================
// Equality
//====================================================================
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Check whether both date/time values fall within the same minute. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
bool IsSameMinute(const datetime a, const datetime b)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return MinuteIndex(a) == MinuteIndex(b);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Check whether both date/time values fall within the same hour. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
bool IsSameHour(const datetime a, const datetime b)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return HourIndex(a) == HourIndex(b);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Check whether both date/time values fall within the same day. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
bool IsSameDay(const datetime a, const datetime b)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return DayIndex(a) == DayIndex(b);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Check whether both date/time values fall within the same week. |
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
bool IsSameWeek(const datetime a, const datetime b)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return WeekIndex(a) == WeekIndex(b);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Check whether both date/time values fall within the same month. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
bool IsSameMonth(const datetime a, const datetime b)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return MonthIndex(a) == MonthIndex(b);
2026-07-18 23:27:05 +03:00
}
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Check whether both date/time values fall within the same quarter |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
bool IsSameQuarter(const datetime a, const datetime b)
2026-07-18 23:27:05 +03:00
{
2026-07-21 21:05:41 +03:00
return QuarterIndex(a) == QuarterIndex(b);
2026-07-18 23:27:05 +03:00
}
2026-07-20 07:45:57 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
//| Check whether both date/time values fall within the same year. |
2026-07-20 07:45:57 +03:00
//+------------------------------------------------------------------+
2026-07-21 21:05:41 +03:00
bool IsSameYear(const datetime a, const datetime b)
2026-07-20 07:45:57 +03:00
{
2026-07-21 21:05:41 +03:00
return YearIndex(a) == YearIndex(b);
2026-07-20 07:45:57 +03:00
}
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
//####################################################################
//# #
//# Calendar Information #
//# #
//####################################################################
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
//| 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;
}
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
//| Returns the number of days in a month of the given year. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
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));
}
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
//| Returns the number of days in a given year. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
int DaysInYear(const int year)
2026-07-18 23:27:05 +03:00
{
2026-07-20 07:45:57 +03:00
return 365 + IsLeapYear(year);
}
//+------------------------------------------------------------------+
//| Returns the number of calendar weeks spanned by the specified |
//| month. |
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
2026-07-18 23:27:05 +03:00
//+------------------------------------------------------------------+
int WeeksInMonth(const int year, const int month)
{
const datetime first = DateFrom(year, month, 1);
2026-07-20 07:45:57 +03:00
return WeekIndex(EndOfMonth(first)) - WeekIndex(first) + 1;
2026-07-18 23:27:05 +03:00
}
2026-07-20 07:45:57 +03:00
//+------------------------------------------------------------------+
//| Returns the number of calendar weeks spanned by the specified |
//| year. |
//| The result depends on TIMEUTILS_FIRST_DAY_OF_WEEK. |
//+------------------------------------------------------------------+
int WeeksInYear(const int year)
{
const datetime first = DateFrom(year, 1, 1);
return WeekIndex(EndOfYear(first)) - WeekIndex(first) + 1;
}
2026-07-18 23:27:05 +03:00
//####################################################################
//# #
2026-07-21 21:05:41 +03:00
//# Formatting & Display #
2026-07-18 23:27:05 +03:00
//# #
//####################################################################
//+------------------------------------------------------------------+
//| Format time with the weekday name => "Wed, 2023.02.14 01:59" |
//+------------------------------------------------------------------+
string t2s(const datetime t, const int mode = TIME_DATE | TIME_MINUTES)
{
const static string days[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
return days[ DayOfWeek(t) ] + ", " + 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);
}
//+------------------------------------------------------------------+
//| Return 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 (monthNo < 1 || monthNo > 12)
? "Undefined monthNo " + (string)monthNo : months[monthNo - 1];
}
//+------------------------------------------------------------------+
//| Return 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 (dayNo < 0 || dayNo > 6)
? "Undefined dayNo " + (string)dayNo : days[dayNo];
}
//+------------------------------------------------------------------+
//| 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" |
//+------------------------------------------------------------------+
2026-07-20 07:45:57 +03:00
string TimeFormat(const datetime t,
const string format = "YYYY.MM.DD hh:mm") {
2026-07-18 23:27:05 +03:00
string retVal;
MqlDateTime dt_struct;
if(format == "" || StringLen(format) == 0) {
Print("invalid format");
return "";
}
if(TimeToStructFast(t, dt_struct) == false) {
Print("TimeToStructFast() 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);
}
2026-07-21 21:05:41 +03:00
//####################################################################
//# #
//# Trading Sessions #
//# #
//####################################################################
enum ENUM_MARKET_SESSION
{
SESSION_NONE = -1,
SESSION_SYDNEY,
SESSION_TOKYO,
SESSION_LONDON,
SESSION_NEW_YORK
};
struct MarketSession
{
int startHour;
int startMinute;
int endHour;
int endMinute;
};
// Standard UTC session times (DST not applied)
static const MarketSession MARKET_SESSIONS[] =
{
{22, 0, 7, 0}, // Sydney
{ 0, 0, 9, 0}, // Tokyo
{ 8, 0, 17, 0}, // London
{13, 0, 22, 0} // New York
};
2026-07-18 23:27:05 +03:00
2026-07-21 21:05:41 +03:00
//====================================================================
// Generic Daily Sessions
//====================================================================
//+------------------------------------------------------------------+
//| Returns true if the specified datetime falls within the |
//| specified recurring daily session [start, end). |
//| |
//| The session repeats every day at the same start and end times. |
//| |
//| If start <= end, the session occurs within a single day. |
//| If start > end, the session spans midnight into the next day. |
//+------------------------------------------------------------------+
bool IsInSession(const datetime t,
const int startHour,
const int startMinute,
const int endHour,
const int endMinute)
{
if(startHour < 0 || startHour > 23 ||
startMinute < 0 || startMinute > 59 ||
endHour < 0 || endHour > 23 ||
endMinute < 0 || endMinute > 59)
return false;
const int current = SecondsSinceMidnight(t);
const int start = startHour * HOURSECS + startMinute * MINSECS;
const int end = endHour * HOURSECS + endMinute * MINSECS;
return (start <= end)
? (current >= start && current < end)
: (current >= start || current < end);
}
//+------------------------------------------------------------------+
//| Returns true if the current server time falls within the |
//| specified recurring daily session [start, end). |
//+------------------------------------------------------------------+
bool IsInSession(const int startHour,
const int startMinute,
const int endHour,
const int endMinute)
{
return IsInSession(
TimeTradeServer(),
startHour,
startMinute,
endHour,
endMinute);
}
//+------------------------------------------------------------------+
//| Returns true if the current server time falls within the |
//| specified recurring daily session [start, end). |
//| |
//| Time strings must be in "HH:MM" or "HH:MM:SS" format. |
//+------------------------------------------------------------------+
bool IsInSession(const string startTime,
const string endTime)
{
const datetime start = DateFromString(startTime);
const datetime end = DateFromString(endTime);
return IsInSession(
TimeTradeServer(),
Hour(start),
Minute(start),
Hour(end),
Minute(end));
}
//====================================================================
// Major FX Sessions
//====================================================================
//+------------------------------------------------------------------+
//| Returns true if the specified datetime falls within one of the |
//| major FX trading sessions. Session hours are defined in UTC. |
//| |
//| utcOffsetSeconds specifies the UTC offset corresponding to the |
//| supplied 'time'. For example, if 'time' is broker server time, |
//| utcOffsetSeconds should be the broker server UTC offset. |
//| |
//| When working with historical data or the Strategy Tester, the |
//| offset should correspond to the historical value of 'time', and |
//| may be obtained from another source (e.g. TimeZoneInfo library). |
//| |
//| Example: |
//| |
//| int offset = TimeTradeServer() - TimeGMT(); |
//| IsInMarketSession(TimeTradeServer(), SESSION_LONDON, offset); |
//+------------------------------------------------------------------+
bool IsInMarketSession(const datetime time,
const ENUM_MARKET_SESSION session,
const int utcOffsetSeconds)
{
const MarketSession s = MARKET_SESSIONS[(int)session];
// Resolve the UTC session boundaries for the same date as
// 'time', then apply the corresponding UTC offset.
const datetime start =
AddSeconds(
WithTime(time, s.startHour, s.startMinute, 0),
utcOffsetSeconds);
const datetime end =
AddSeconds(
WithTime(time, s.endHour, s.endMinute, 0),
utcOffsetSeconds);
return IsInSession(
time,
Hour(start),
Minute(start),
Hour(end),
Minute(end));
}
//+------------------------------------------------------------------+
//| Returns true if the current server time falls within one of the |
//| major FX trading sessions. Session hours are defined in UTC. |
//+------------------------------------------------------------------+
bool IsInMarketSession(const ENUM_MARKET_SESSION session)
{
const datetime serverTime = TimeTradeServer();
return IsInMarketSession(
serverTime,
session,
(int)(serverTime - TimeGMT()));
}
//+------------------------------------------------------------------+
//| Return the active major FX market session. Session hours are |
//| defined in UTC. |
//| |
//| utcOffsetSeconds specifies the UTC offset corresponding to the |
//| supplied 'time'. Returns SESSION_NONE if no session is active. |
//+------------------------------------------------------------------+
ENUM_MARKET_SESSION CurrentMarketSession(const datetime time,
const int utcOffsetSeconds)
{
for(int i = 0; i < ArraySize(MARKET_SESSIONS); i++)
{
if(IsInMarketSession(
time,
(ENUM_MARKET_SESSION)i,
utcOffsetSeconds))
return (ENUM_MARKET_SESSION)i;
}
return SESSION_NONE;
}
//+------------------------------------------------------------------+
//| Return the active major FX market session using the current |
//| trade server time and its corresponding UTC offset. |
//+------------------------------------------------------------------+
ENUM_MARKET_SESSION CurrentMarketSession()
{
const datetime serverTime = TimeTradeServer();
return CurrentMarketSession(
serverTime,
(int)(serverTime - TimeGMT()));
}
//+------------------------------------------------------------------+
//| Return the display name of the specified market session. |
//+------------------------------------------------------------------+
string MarketSessionName(const ENUM_MARKET_SESSION session)
{
switch(session)
{
case SESSION_SYDNEY: return "Sydney";
case SESSION_TOKYO: return "Tokyo";
case SESSION_LONDON: return "London";
case SESSION_NEW_YORK: return "New York";
}
return "Unknown";
}
//+------------------------------------------------------------------+
//| Returns true if the specified datetime falls within the overlap |
//| of the two specified major FX trading sessions. Session hours |
//| are defined in UTC. |
//| |
//| utcOffsetSeconds specifies the UTC offset corresponding to the |
//| supplied 'time'. Returns false if no session overlap. |
//+------------------------------------------------------------------+
bool IsSessionOverlap(const datetime time,
const ENUM_MARKET_SESSION session1,
const ENUM_MARKET_SESSION session2,
const int utcOffsetSeconds)
{
return IsInMarketSession(time, session1, utcOffsetSeconds) &&
IsInMarketSession(time, session2, utcOffsetSeconds);
}
//+------------------------------------------------------------------+
//| Returns true if the current trade server time falls within the |
//| overlap of the two specified major FX trading sessions. Session |
//| hours are defined in UTC. |
//+------------------------------------------------------------------+
bool IsSessionOverlap(const ENUM_MARKET_SESSION session1,
const ENUM_MARKET_SESSION session2)
{
return IsInMarketSession(session1) &&
IsInMarketSession(session2);
}
//####################################################################
//# #
//# Economic Calendar / News #
//# #
//####################################################################
//====================================================================
// News Checks
//====================================================================
//+------------------------------------------------------------------+
//| Return true if checkTime falls within the specified window |
//| around eventTime. |
//+------------------------------------------------------------------+
bool IsNearNews(const datetime checkTime,
const datetime eventTime,
const int minutesBefore,
const int minutesAfter)
{
return checkTime >= eventTime - minutesBefore * (int)MINSECS &&
checkTime < eventTime + minutesAfter * (int)MINSECS;
}
//+------------------------------------------------------------------+
//| Return true if checkTime falls within the specified window |
//| around any economic event having at least the specified |
//| importance. |
//+------------------------------------------------------------------+
bool IsNearNews(const datetime checkTime,
const int minutesBefore,
const int minutesAfter,
const ENUM_CALENDAR_EVENT_IMPORTANCE minImportance = CALENDAR_IMPORTANCE_HIGH)
{
MqlCalendarValue values[];
const datetime time_from = SubDays(checkTime, 3);
const datetime time_to = AddDays(checkTime, 3);
if(!CalendarValueHistory(values, time_from, time_to))
return false;
const int before = minutesBefore * MINSECS;
const int after = minutesAfter * MINSECS;
const int count = ArraySize(values);
for(int i = 0; i < count; i++)
{
MqlCalendarEvent event;
CalendarEventById(values[i].event_id, event);
if(event.importance < minImportance)
continue;
if(checkTime >= values[i].time - before &&
checkTime < values[i].time + after)
return true;
}
return false;
}
//====================================================================
// Time Until News
//====================================================================
//+------------------------------------------------------------------+
//| Return the number of seconds until the next economic event. |
//| |
//| The input array is assumed to be already filtered (e.g. by |
//| country, currency, importance, etc.). |
//| |
//| Returns -1 if no future event exists. |
//+------------------------------------------------------------------+
int TimeUntilNews(const datetime from,
const MqlCalendarValue &events[])
{
const int count = ArraySize(events);
if(count == 0)
return -1;
datetime nextTime = LONG_MAX; // the nearest future event.
for(int i = 0; i < count; i++)
{
const datetime eventTime = events[i].time;
if(eventTime >= from && eventTime < nextTime)
nextTime = eventTime;
}
if(nextTime == LONG_MAX)
return -1;
return (int)(nextTime - from);
}
//+------------------------------------------------------------------+
//| Return the number of seconds until the next economic event |
//| having at least the specified importance. |
//| |
//| Returns -1 if no future event exists. |
//+------------------------------------------------------------------+
int TimeUntilNews(const datetime from,
const ENUM_CALENDAR_EVENT_IMPORTANCE minImportance = CALENDAR_IMPORTANCE_HIGH)
{
MqlCalendarValue values[];
if(!CalendarValueHistory(values, from, AddWeeks(from, 1)))
return -1;
datetime nextTime = LONG_MAX;
const int count = ArraySize(values);
for(int i = 0; i < count; i++)
{
MqlCalendarEvent event;
if(!CalendarEventById(values[i].event_id, event))
continue;
if(event.importance < minImportance)
continue;
if(values[i].time >= from && values[i].time < nextTime)
nextTime = values[i].time;
}
if(nextTime == LONG_MAX)
return -1;
return (int)(nextTime - from);
}
#undef MINSECS
#undef HOURSECS
#undef DAYSECS
#undef WEEKSECS
2026-07-18 23:27:05 +03:00
#undef DAYS_PER_4_YEARS
#undef DAYS_PER_400_YEARS
#undef DAYS_TO_1970
#undef MARCH1_BASED_DOY
2026-07-21 21:05:41 +03:00
#undef WEEK_OFFSET
2026-07-18 23:27:05 +03:00
#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( Year(t) );
Print( Month(t) );
Print( Day(t) );
Print( Hour(t) );
Print( Minute(t) );
Print( Second(t) );
Print( DayOfWeek(t) );
Print( DayOfYear(t) );
MqlDateTime dt[1] = {};
TimeToStructFast(t, dt[0]);
ArrayPrint(dt);
dt[0].year += 1;
Print(StructToTimeFast(dt[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
*/
//+------------------------------------------------------------------+