Learning Boost Library Date Intervals through C++ Source Code

After discussing duration classes yesterday, today we will learn about date intervals in Boost. In Boost, boost::gregorian::date_period represents a left-closed, right-open interval on the timeline, with its two endpoints being date objects. A detailed introduction is shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

Next, let’s take a look at its source code. First, we found its definition and discovered that it is an alias, as shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

From this, we can see that it is actually the boost::date_time::period template class, which takes two type parameters: date and date_duration (if you are unclear about these two classes, you can refer to my previous articles). Next, let’s look at the definition of this template class, as shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

On the left side of the image are the member variables and methods of the class, while the right side shows the specific definitions. Let’s analyze them one by one, starting with its two member variables begin_ and last_, defined as shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

From the class definition above, we know that the point_rep template parameter is passed as the date class, so both begin_ and last_ variables are date objects, representing the start and end dates of the date interval, respectively. Now let’s look at its constructor, as shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

From the image, we can see that it has two constructors: one constructs the date interval using two dates, the start date and the end date, while the other constructs the date interval using the start date and a duration (from the class definition, we can see that duration_rep is actually the date_duration class). Moreover, from this constructor, we also understand why it was initially stated that this date interval is left-closed and right-open, because when storing the value of the last_ variable, it actually stores the given end date value minus one unit.

Finally, let’s take a look at its member methods. First, we have the begin, end, and last functions, as shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

From the code, we can see that begin and last return the actual stored start and end dates, while end returns the day after the stored end date. Then we have the is_null and length functions, as shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

From the function definitions, if a left endpoint is larger than the right endpoint or the date length is 0 when constructing the date interval, the is_null function will return true. The length function returns the length of the date interval (in days), and if the length is negative, it indicates that this is an invalid date interval. Then we have two comparison operations; from the function definitions, it is clear that the comparison is based not on the length of the date intervals but on the endpoints. Only if both the start and end dates of one date interval are equal to the start and end dates of another date interval will the two intervals be considered equal. Only if the end date of one interval is less than the start date of another interval will the first interval be considered less than the second. The specific code definitions are shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

Next is the shift function, which shifts the date interval by n days while keeping the length unchanged, defined as shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

There is also the expand function, which extends the date interval by n days on both ends, effectively increasing the interval length by 2n days. The specific definition is shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

Next are two contains methods, which determine whether the date interval contains another date or interval. The definitions are shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

The is_adjacent method checks whether two date intervals are adjacent, with the function definition shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

The is_before and is_after methods determine whether the date interval is before or after a certain date, defined as shown in the images below:

Learning Boost Library Date Intervals through C++ Source Code

Learning Boost Library Date Intervals through C++ Source Code

The intersects method checks whether two date intervals have an intersection, with the definition shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

The intersection method returns the intersection of two date intervals; if there is no intersection, it returns an invalid interval. The function definition is shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

The merge method returns the union of two date intervals; if the two date intervals have no intersection or are not adjacent, it returns an invalid interval, defined as shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

The span method merges two date intervals and the gap between them (essentially taking the smaller start date and the larger end date of the two intervals to form a new date interval), with the function definition shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

At this point, we have a clear understanding of the date interval class. Now, let’s start writing code to test the actual effects of these interface methods.

#include <iostream>
#include <boost/date_time/gregorian/gregorian.hpp>

using namespace boost::gregorian;

int main()
{
    // Define two date objects
    date d1(2025, 5, 1);
    date d2(2025, 9, 23);
    // Define a duration object
    days ds(40);
    // Define three date period objects
    date_period dp1(d1, d2); // 2025-05-01/2025-09-22
    date_period dp2(d1, ds); // 2025-05-01/2025-6-9
    date_period dp3(dp2);    // 2025-05-01/2025-6-9
    // Define two invalid date period objects
    date_period dp4(d1, days(-2));
    date_period dp5(d2, d1);

    std::cout << "dp1 begin date: " << dp1.begin() << ", dp1 last date: " << dp1.last()
              << ", dp1 end date: " << dp1.end() << std::endl;
    std::cout << "dp1 is null? " << (dp1.is_null() ? "Y" : "N") << ", dp1 length: " << dp1.length() << std::endl;
    std::cout << "dp4 is null? " << (dp4.is_null() ? "Y" : "N") << ", dp4 length: " << dp4.length() << std::endl;
    std::cout << "dp2 == dp3 ? " << (dp2 == dp3 ? "Y" : "N") << std::endl;
    std::cout << "dp1 < dp2 ? " << (dp1 < dp2 ? "Y" : "N") << std::endl;

    std::cout << "dp1: " << dp1 << std::endl;
    // Shift by 5 days
    dp1.shift(days(5)); // Becomes 2025-05-06/2025-9-27
    std::cout << "after shift dp1: " << dp1 << std::endl;
    std::cout << "dp2: " << dp2 << std::endl;
    // Expand by 5 days
    dp2.expand(days(5)); // Becomes 2025-04-26/2025-6-14
    std::cout << "after expand dp2: " << dp2 << std::endl;
    // Check if 2025-05-10 is within dp2 date interval
    std::cout << "dp2 contains 2025-05-10? " << (dp2.contains(date(2025, 5, 10)) ? "Y" : "N") << std::endl;
    // Check if date interval dp1 is within dp2 date interval
    std::cout << "dp2 contains dp1? " << (dp2.contains(dp1) ? "Y" : "N") << std::endl;
    // Check if two date intervals are adjacent
    date_period dp6(d1, days(3));
    date_period dp7(date(2025, 5, 4), days(10));
    std::cout << "dp6: " << dp6 << ", dp7: " << dp7 << ", is adjacent? " << (dp6.is_adjacent(dp7) ? "Y" : "N") << std::endl;
    // Check if date interval dp6 is before date 2025-05-30
    std::cout << "dp6 is before 2025-05-30? " << (dp6.is_before(date(2025, 5, 30)) ? "Y" : "N") << std::endl;
    // Check if date interval dp6 is after date 2025-04-20
    std::cout << "dp6 is after 2025-04-20? " << (dp6.is_after(date(2025, 4, 20)) ? "Y" : "N") << std::endl;
    // Check if two date intervals intersect and print intersection
    std::cout << "dp1 and dp2 intersects? " << (dp1.intersects(dp2) ? "Y" : "N")
              << ", dp1 and dp2 intersection: " << dp1.intersection(dp2) << std::endl;
    std::cout << "dp1 and dp6 intersects? " << (dp1.intersects(dp6) ? "Y" : "N")
              << ", dp1 and dp6 intersection: " << dp1.intersection(dp6) << std::endl;
    // Return the union of two date intervals
    std::cout << "dp1 and dp2 merge: " << dp1.merge(dp2) << std::endl;
    // Merge two date intervals and the gap between them
    std::cout << "dp1 and dp6 span: " << dp1.span(dp6) << std::endl;
    // Convert to string
    std::string s = to_simple_string(dp7);
    std::cout << "dp7 string: " << s << std::endl;
    return 0;

The compilation and execution results of the code are shown in the image below:

Learning Boost Library Date Intervals through C++ Source Code

That concludes our discussion on date intervals for today. If you have any questions, feel free to leave a comment for discussion. We will look at other topics when we have time.

Leave a Comment