Libraries: High-Performance Time Functions (TimeUtils)

 

High-Performance Time Functions (TimeUtils):

High-performmance functions for dealing with time.

Author: amrali

 
Thanks for developing the library, I will try
 

Although, I suspect its irrelevant due to the times being actually calculated, here is a code that does the correct "IsLeapYear" calculations a bit more refined:


// Months
#define JANUARY                                     mqlplus_month_JANUARY
#define FEBRUARY                                    mqlplus_month_FEBRUARY
#define MARCH                                       mqlplus_month_MARCH
#define APRIL                                       mqlplus_month_APRIL
#define MAY                                         mqlplus_month_MAY
#define JUNE                                        mqlplus_month_JUNE
#define JULY                                        mqlplus_month_JULY
#define AUGUST                                      mqlplus_month_AUGUST
#define SEPTEMBER                                   mqlplus_month_SEPTEMBER
#define OCTOBER                                     mqlplus_month_OCTOBER
#define NOVEMBER                                    mqlplus_month_NOVEMBER
#define DECEMBER                                    mqlplus_month_DECEMBER

#define ENUM_MONTH_OF_YEAR mqlplus_enum_month_of_year

enum ENUM_MONTH_OF_YEAR
{
    mqlplus_month_JANUARY                           = 0x01,             // January
    mqlplus_month_FEBRUARY                          = 0x02,             // February
    mqlplus_month_MARCH                             = 0x03,             // March
    mqlplus_month_APRIL                             = 0x04,             // April
    mqlplus_month_MAY                               = 0x05,             // May
    mqlplus_month_JUNE                              = 0x06,             // June
    mqlplus_month_JULY                              = 0x07,             // July
    mqlplus_month_AUGUST                            = 0x08,             // August
    mqlplus_month_SEPTEMBER                         = 0x09,             // September
    mqlplus_month_OCTOBER                           = 0x0A,             // October
    mqlplus_month_NOVEMBER                          = 0x0B,             // November
    mqlplus_month_DECEMBER                          = 0x0C              // December
};


const int mqlplus_DaysInMonth(const ENUM_MONTH_OF_YEAR month, const int year) 
{
    switch(month)
    {
        case JANUARY:   return(31);
        case FEBRUARY:  return(28 + (((year % 4) == NULL) && ((year % 100) != NULL)) + (((year % 100) == NULL) && ((year % 400) != NULL)) + ((year % 400) == NULL));
        case MARCH:     return(31);
        case APRIL:     return(30);
        case MAY:       return(31);
        case JUNE:      return(30);
        case JULY:      return(31);
        case AUGUST:    return(31);
        case SEPTEMBER: return(30);
        case OCTOBER:   return(31);
        case NOVEMBER:  return(30);
        case DECEMBER:  return(31);
        default:        return(NULL);
    }
}
 
Dominik Egert #:

Although, I suspect its irrelevant due to the times being actually calculated, here is a code that does the correct "IsLeapYear" calculations a bit more refined:


Thanks for you idea, However I am seeing this is more elegant:

bool IsLeapYear(const int year)
  {
   // From: https://www.youtube.com/watch?v=0s9F4QWAl-E&t=1790s
   int d = (year % 100 != 0) ? 4 : 16;
   return (year & (d - 1)) == 0;
  }

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];
  }

and faster, as the check for leap year requires 1 branching (comparison).

Also, the check for February is embbeded into the lookup array.

or, as one-liner :

bool IsLeapYear(const int year)
  {
   return (year & ((year % 100 != 0) ? 3 : 15)) == 0;
  }

Edit:
Your code returns 29 days for Feb 2100 (wrong).
 
amrali #:

Thanks for you idea, However I am seeing this is more elegant:

and faster, as the check for leap year requires 1 branching (comparison).

Also, the check for February is embbeded into the lookup array.

or, as one-liner :


Edit:
Your code returns 29 days for Feb 2100 (wrong).
Ah, so beautiful...

Thank you for checking. I'll fix my code.
 
Dominik Egert #:
Ah, so beautiful...

Thank you for checking. I'll fix my code.

benchmark:

bool IsLeapYear(const int year)
  {
   return (year & ((year % 100 != 0) ? 3 : 15)) == 0;
  }
//+------------------------------------------------------------------+
int DaysInMonth_v1(const int year, const int month)
  {
   switch(month)
     {
      case 2:
         return 28 + IsLeapYear(year);
      case 4:
      case 6:
      case 9:
      case 11:
         return 30;
      default:
         return 31;
     }
  }
//+------------------------------------------------------------------+
int DaysInMonth_v2(const int year, const int month)
  {
   const int dim[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
   return (month == 2 && IsLeapYear(year)) ? 29 : dim[month % 13];
  }
//+------------------------------------------------------------------+
int DaysInMonth_v3(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];
  }
                     
// Compiler Version: 4620, X64 Regular
// 13th Gen Intel Core i7-13700KF, AVX2 + FMA3
//  3.58 ns, checksum = 108596907345   // DaysInMonth_v1
//  1.48 ns, checksum = 108596907345   // DaysInMonth_v2
//  1.24 ns, checksum = 108596907345   // DaysInMonth_v3
the switch statement has more branches.
Files:
 

Forum on trading, automated trading systems and testing trading strategies

Libraries: High-Performance Time Functions (TimeUtils)

amrali, 2024.12.04 22:49

int DaysInMonth_v2(const int year, const int month)
  {
   static const int dim[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
   return (month == 2 && IsLeapYear(year)) ? 29 : dim[month % 13];
  }
int DaysInMonth_v4(const int year, const int month)
  {
   if (month == 2)
      return(28 + IsLeapYear(year));            
      
   return(30 | (month ^ (month >> 3)));
  }
 
fxsaber #:

Thanks!

 Compiler Version: 4620, X64 Regular
 13th Gen Intel Core i7-13700KF, AVX2 + FMA3
  3.54 ns, checksum = 108596882915   // DaysInMonth_v1
  1.51 ns, checksum = 108596882915   // DaysInMonth_v2
  1.26 ns, checksum = 108596882915   // DaysInMonth_v3
  1.08 ns, checksum = 108596882915   // DaysInMonth_v4
 

Update 5 December 2024 - version 1.15

1. optimized calculations in DaysInMonth() function.

2. added new functions:

//+==================================================================+
//| Nth() Weekday Of The Month                                       |
//+==================================================================+
datetime FirstWeekdayOfTheMonth(datetime t, ENUM_DAY_OF_WEEK weekday = SUNDAY)
datetime LastWeekdayOfTheMonth(datetime t, ENUM_DAY_OF_WEEK weekday = SUNDAY)
datetime NthWeekdayOfTheMonth(datetime t, int Nth, ENUM_DAY_OF_WEEK weekday = SUNDAY)

//+==================================================================+
//| Add() Units                                                      |
//+==================================================================+
datetime AddBusinessDays(datetime t, int amount)

//+==================================================================+
//| Sub() Units                                                      |
//+==================================================================+
datetime SubBusinessDays(datetime t, int amount)

//+==================================================================+
//| DifferenceIn() Units                                             |
//+==================================================================+
int DifferenceInBusinessDays(datetime beginTime, datetime endTime)

//+==================================================================+
//| Misc                                                             |
//+==================================================================+
datetime GetNthWeekdayInYearMonth(iYear, iMonth, Nth, weekday = SUNDAY)
datetime GetNthSundayInYearMonth(iYear, iMonth, Nth)

//+==================================================================+
//| Formating Time to String                                         |
//+==================================================================+
string SecondsToString(int seconds)

3. minor bug fixes

 
datetime CreateDateTime(
   const int year,           // Year
   const int mon,            // Month
   const int day,            // Day
   const int hour = 0,       // Hour
   const int min = 0,        // Minutes
   const int sec = 0         // Seconds
   )
  {
// MqlDateTime dt = {year, mon, day, hour, min, sec}
// return StructToTime(dt);

//   static const uint Months[] = {0, 11512676, 11512180, 11511728, 11511232, 11510750, 11510256,
//                                    11509774, 11509280, 11508781, 11508302, 11507806, 11507326
//                                };
                                
   static const uint Months[] = {0, 11512692, 11512196, 11511744, 11511248, 11510766, 11510272,
                                    11509790, 11509296, 11508797, 11508318, 11507822, 11507342
                                };
//   return (((year * 5844 - Months[mon]) >> 4) + day - 1) * DAYSECS + (hour * HOURSECS + min * MINSECS + sec);                                                                
   return (((year * 5844 - Months[mon]) >> 4) + day) * DAYSECS + (hour * HOURSECS + min * MINSECS + sec);
  }
 
fxsaber #:
Watch out:
1970*5844 (11,512,680) - 11,512,692 = minus 
There is right-shift for the minus.