Hemil
Hemil

Reputation: 1026

How to find the date of the previous monday in C++

I want to make a program which takes no input and returns the date of the previous Monday. (I don't care about time zones. And I am only worried about Gregorian calendar). I am using date by Howard Hinnant. This is how I am doing it currently:

#include <iostream>
#include <date/date.h>

int main() {

    auto todays_day = date::year_month_weekday(date::floor<date::days>(std::chrono::system_clock::now()));

    auto todays_date = date::floor<date::days>(std::chrono::system_clock::now());

    int offset = 0;

    auto weekday = todays_day.weekday();

    if(weekday == date::Tuesday)
        offset = 1;
    else if (weekday == date::Wednesday)
        offset = 2;
    else if (weekday == date::Thursday)
        offset = 3;
    else if (weekday == date::Friday)
        offset = 4;
    else if (weekday == date::Saturday)
        offset = 5;
    else if (weekday == date::Sunday)
        offset = 6;

    auto lastMonday = date::year_month_day(todays_date - date::days(offset));

    std::cout << lastMonday;
}

Is there a better way to do this without boost::previous_weekday? (It's not a requirement not to use boost. I am just wondering if it is possible)

Upvotes: 3

Views: 1349

Answers (1)

Howard Hinnant
Howard Hinnant

Reputation: 219428

The key to understanding how to do this more simply is knowing this one fact about Howard Hinnant's date library:

weekday difference is circular (or modulo 7 if you prefer). That is, any weekday subtracted from any weekday results in a number of days in the range [0, 6]. This effectively hides the underlying encoding of weekday.

Thus there is no need to translate [Monday, Sunday] into [0, 6] (or any other encoding):

#include "date/date.h"
#include <iostream>

int
main()
{
    auto todays_date = date::floor<date::days>(std::chrono::system_clock::now());
    date::year_month_day lastMonday = todays_date -
                                      (date::weekday{todays_date} - date::Monday);
    std::cout << lastMonday << '\n';
}

Instead you just have to decide how many days you need to subtract from a sys_days (todays_date in this example). That number of days is today's weekday minus Monday. If today is Monday, the result is days{0}. If today is Sunday, the result is days{6}. We could just as well be talking about finding the previous Friday. The logic would not change.

Also, one can directly convert a sys_days to a weekday. No need to go though year_month_weekday.

The code in the OP's question considers the "previous Monday" to be today if today happens to be a Monday. And that is fine. That is what is desired in many "previous weekday" algorithms. And it is the logic I have coded above.

But it is also common to want the previous-weekday-algorithm to result in last week if the weekday you are seeking is today. I.e. if today is Monday, compute a week ago instead of today. That too is easily doable, and by pretty much the same algorithm. One just has to subtract a day at the beginning of the algorithm if you desire this behavior:

auto todays_date = ...
todays_date -= date::days{1};
date::year_month_day lastMonday = ...

Upvotes: 7

Related Questions