Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the number of trading days in between two days

Tags:

c++

c++11

boost

i'm trying to get the number of trading dates between two dates which will only exclude the weekends and won't consider any holidays. I'm using Boost and c++11 standards.

using namespace boost::gregorian;
long dateDifference( string start_date, string end_date ) {

            date _start_date(from_simple_string(start_date));
            date _end_date(from_simple_string(end_date));


            long difference = ( _start_date - _end_date ).days();

            return difference;

        }

This just returns the number of days between two dates without considering weekends. Can someone point me in the right direction. I can't seem to figure out the solution.

Thanks, Maxx

like image 448
Maxx Avatar asked Dec 15 '22 00:12

Maxx


1 Answers

O(1) solution with no loops:

#include <boost/date_time.hpp>
using namespace std;
using namespace boost::gregorian;

long countWeekDays( string d0str, string d1str ) {
    date d0(from_simple_string(d0str));
    date d1(from_simple_string(d1str));
    long ndays = (d1-d0).days() + 1; // +1 for inclusive
    long nwkends = 2*( (ndays+d0.day_of_week())/7 ); // 2*Saturdays
    if( d0.day_of_week() == boost::date_time::Sunday ) ++nwkends;
    if( d1.day_of_week() == boost::date_time::Saturday ) --nwkends;
    return ndays - nwkends;
}

The basic idea is to first count all Saturdays, which is conveniently given by the formula (ndays+d0.day_of_week())/7. Doubling this gives you all Saturdays and Sundays, except in the cases when the start and end dates may fall on a weekend, which is adjusted for by 2 simple tests.

To test it:

#include <iostream>
#include <cassert>
#include <string>

//      January 2014    
//  Su Mo Tu We Th Fr Sa
//            1  2  3  4
//   5  6  7  8  9 10 11
//  12 13 14 15 16 17 18
//  19 20 21 22 23 24 25
//  26 27 28 29 30 31
int main()
{
  assert(countWeekDays("2014-01-01","2014-01-01") == 1);
  assert(countWeekDays("2014-01-01","2014-01-02") == 2);
  assert(countWeekDays("2014-01-01","2014-01-03") == 3);
  assert(countWeekDays("2014-01-01","2014-01-04") == 3);
  assert(countWeekDays("2014-01-01","2014-01-05") == 3);
  assert(countWeekDays("2014-01-01","2014-01-06") == 4);
  assert(countWeekDays("2014-01-01","2014-01-10") == 8);
  assert(countWeekDays("2014-01-01","2014-01-11") == 8);
  assert(countWeekDays("2014-01-01","2014-01-12") == 8);
  assert(countWeekDays("2014-01-01","2014-01-13") == 9);
  assert(countWeekDays("2014-01-02","2014-01-13") == 8);
  assert(countWeekDays("2014-01-03","2014-01-13") == 7);
  assert(countWeekDays("2014-01-04","2014-01-13") == 6);
  assert(countWeekDays("2014-01-05","2014-01-13") == 6);
  assert(countWeekDays("2014-01-06","2014-01-13") == 6);
  assert(countWeekDays("2014-01-07","2014-01-13") == 5);
  cout << "All tests pass." << endl;
  return 0;
}

This works for any date range in the Gregorian calendar, which boost currently supports for years 1400-10000. Note that different countries have adopted the Gregorian calendar at different times. For example the British switched from the Julian to the Gregorian calendar in September of 1752, so their calendar for that month looks like

   September 1752
Su Mo Tu We Th Fr Sa
       1  2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
like image 56
Matt Avatar answered Dec 17 '22 14:12

Matt