I am new to c++, so I am wondering whether there is some library which could help deal with dates more fluently.
I have a fairly plain task. I have a starting date in different values and I have to get what date it will be when I increase the date by a random number of days.
I figured mktime and time_t objects seams to be helpful with what I am trying to do. If they are the answer could someone give me a link to a good guide?
Boost: Boost.Date
Qt framework: QDateTime
Codeproject hosted: CTime
If you want handle date and time basically yourself: C/C++ standard
library
A day is usually 86400 seconds (except for leap seconds) . You can add that to a time_t and get a new time_t etc. Then you can use mktime & localtime to convert it to struct tm which is displayable with strftime and could be parsable with strptime
Well, there is either the Boost Date and time module. Of if your compiler is new enough there is the C++11 chrono namespace.
I just wrote my own function to add Days, Months and Years to an existing DATE class. I couldn't test it yet, but maybe it helps:
bool DATE::add(int Day, int Month, int Year){
int DaysPerMonth[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
this -> Day += Day;
while(this -> Day > DaysPerMonth[ this-> Month ]){
if((this -> Year % 4 == 0 && this -> Year % 100 != 0) || this -> Year % 400 == 0){
DaysPerMonth[2] = 29;
}
this -> Day -= DaysPerMonth[ this-> Month ];
this -> Month++;
if(this -> Month > 12){
this -> Month = 1;
this -> Year++;
}
}
this -> Month = ( this -> Month + (Month % 12));
this -> Year = ( this -> Year + Year + (Month/12));
if((this -> Year % 4 == 0 && this -> Year % 100 != 0) || this -> Year % 400 == 0){
DaysPerMonth[2] = 29;
// check pathologic case wether date is 1 of March and added Year targets switchyear
if( this -> Day == 1 && this -> Month == 3){
this -> Day = 29;
this -> Month = 2;
}
}
if(this -> Month < 1 || this -> Month > 12 || this -> Day < 1 || this -> Day > DaysPerMonth[this->Month]){
valid = false;
cerr << "something went wrong, calculated Date is: " << this -> Day << "."<< this -> Month << "." << this -> Year << endl << flush;
return false;
}else{
return true;
}
}
A new answer for a decade-old question because times have changed and tools have gotten better.
In C++20, a date can be represented in several different succinct and useful ways.
std::chrono::sys_days
std::chrono::year_month_day
std::chrono::year_month_weekday
(this is not an exhaustive list)
Each data structure above represents a date, but has advantages and disadvantages, much like we have several container types that represent a sequence of values (vector, list, deque, etc.) with advantages and disadvantages.
For adding days to a date, sys_days is the clear best choice for a date representation. sys_days is nothing but a count of days since (or before) 1970-01-01. It is a type alias for:
time_point<system_clock, days>
where days is a std::chrono::duration:
duration<signed integer type of at least 25 bits, ratio_multiply<ratio<24>, hours::period>>
So adding days to sys_days is simply integral arithmetic under the hood.
And C++20 allows seamless conversion between {year, month, day} concepts and sys_days. So this looks like:
sys_days tp = sys_days{January/30/2022} + days{400}; // tp = 2023-03-06
Integrals can be used as inputs to the above formula. However when working with <chrono> it is best to try and stay within the strong type system of <chrono>.:
int y = 2022;
int m = 1;
int d = 30;
int num_days = 400;
sys_days tp = sys_days{month(m)/d/y} + days{num_days}; // tp = 2023-03-06
In any event, tp can be easily observed by just printing it out:
cout << tp << '\n';
Output:
2023-03-06
Other formatting options are available, and programmatic access to the values for the year, month and day are also available. It is best to keep these values within the chrono strong types year, month and day, but conversions to integral types are also available.
A portable method using the standard ctime header, is to construct an mt struct using localtime() (or gmtime() to use UTC time). Then, add the number of days to the tm_day member and convert the structure back to a time using mktime().
The tm_day member represents the day of the month, but mktime allows it to exceed the number of days in a month, and even allows it to be negative in case it is necessary to subtract days from the date, so you do not have to guard for month-wrapping.
An example:
#include <ctime>
time_t add_days(const time_t& time_value, int days) {
tm tm_value = *localtime(&time_value);
tm_value.tm_mday += days;
return mktime(&tm_value);
}
A downside of this method can be that the std libraries might not implement localtime() in a thread-safe way. This can be fixed by using localtime_r() instead, but that is less portable.
Related
https://www.timeanddate.com/date/weekday.html computes various facts about a day of the year, for example:
Given an arbitrary date, how can these numbers be computed with the C++20 chrono specification?
This is remarkably easy with the C++20 chrono specification. Below I show a function which inputs an arbitrary date, and prints this information to cout. Though at the time of this writing, the C++20 chrono specification isn't yet shipping, it is approximated by a free, open-source library. So you can experiment with it today, and even include it in shipping applications as long as you adopt C++11 or later.
This answer will take the form of a function:
void info(std::chrono::sys_days sd);
sys_days is a day-precision time_point in the system_clock family. That means it is simply a count of days since 1970-01-01 00:00:00 UTC. The type alias sys_days is new with C++20, but the underlying type has been available since C++11 (time_point<system_clock, duration<int, ratio<86400>>>). If you use the open-source C++20 preview library, sys_days is in namespace date.
The code below assumes function-local:
using namespace std;
using namespace std::chrono;
to reduce verbosity. If you are experimenting with the open-source C++20 preview library, also assume:
using namespace date;
Heading
To output the first two lines is simple:
cout << format("{:%d %B %Y is a %A}\n", sd)
<< "\nAdditional facts\n";
Just take the date sd and use format with the familiar strftime/put_time flags to print out the date and text. The open-source C++20 preview library hasn't yet integrated the fmt library, and so uses the slightly altered format string "%d %B %Y is a %A\n".
This will output (for example):
26 December 2019 is a Thursday
Additional facts
Common intermediate results computed once
This section of the function is written last, because one doesn't yet know what computations will be needed multiple times. But once you know, here is how to compute them:
year_month_day ymd = sd;
auto y = ymd.year();
auto m = ymd.month();
weekday wd{sd};
sys_days NewYears = y/1/1;
sys_days LastDayOfYear = y/12/31;
We will need the year and month fields of sd, and the weekday (day of the week). It is efficient to compute them once and for all in this manner. We will also need (multiple times) the first and last days of the current year. It is hard to tell at this point, but it is efficient to store these values as type sys_days as their subsequent use is only with day-oriented arithmetic which sys_days is very efficient at (sub-nanosecond speeds).
Fact 1: day number of year, and number of days left in year
auto dn = sd - NewYears + days{1};
auto dl = LastDayOfYear - sd;
cout << "* It is day number " << dn/days{1} << " of the year, "
<< dl/days{1} << " days left.\n";
This prints out the day number of the year, with January 1 being day 1, and then also prints out the number of days remaining in the year, not including sd. The computation to do this is trivial. Dividing each result by days{1} is a way to extract the number of days in dn and dl into an integral type for formatting purposes.
Fact 2: Number of this weekday and total number of weekdays in year
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
auto total_wd = (last_wd - first_wd)/weeks{1} + 1;
auto n_wd = (sd - first_wd)/weeks{1} + 1;
cout << format("* It is {:%A} number ", wd) << n_wd << " out of "
<< total_wd << format(" in {:%Y}.\n}", y);
wd is the day of the week (Monday thru Sunday) computed at the top of this article. To perform this computation we first need the dates of the first and last wd's in the year y. y/1/wd[1] is the first wd in January, and y/12/wd[last] is the last wd in December.
The total number of wds in the year is just the number of weeks between these two dates (plus 1). The sub-expression last_wd - first_wd is the number of days between the two dates. Dividing this result by 1 week results in an integral type holding the number of weeks between the two dates.
The week number is done the same way as the total number of weeks except one starts with the current day instead of the last wd of the year: sd - first_wd.
Fact 3: Number of this weekday and total number of weekdays in month
first_wd = y/m/wd[1];
last_wd = y/m/wd[last];
total_wd = (last_wd - first_wd)/weeks{1} + 1;
n_wd = (sd - first_wd)/weeks{1} + 1;
cout << format("* It is {:%A} number }", wd) << n_wd << " out of "
<< total_wd << format(" in {:%B %Y}.\n", y/m);
This works just like Fact 2, except we start with the first and last wds of the year-month pair y/m instead of the entire year.
Fact 4: Number of days in year
auto total_days = LastDayOfYear - NewYears + days{1};
cout << format("* Year {:%Y} has ", y) << total_days/days{1} << " days.\n";
The code pretty much speaks for itself.
Fact 5 Number of days in month
total_days = sys_days{y/m/last} - sys_days{y/m/1} + days{1};
cout << format("* {:%B %Y} has ", y/m) << total_days/days{1} << " days.\n";
The expression y/m/last is the last day of the year-month pair y/m, and of course y/m/1 is the first day of the month. Both are converted to sys_days so that they can be subtracted to get the number of days between them. Add 1 for the 1-based count.
Use
info can be used like this:
info(December/26/2019);
or like this:
info(floor<days>(system_clock::now()));
Here is example output:
26 December 2019 is a Thursday
Additional facts
* It is day number 360 of the year, 5 days left.
* It is Thursday number 52 out of 52 in 2019.
* It is Thursday number 4 out of 4 in December 2019.
* Year 2019 has 365 days.
* December 2019 has 31 days.
Edit
For those who are not fond of the "conventional syntax", there is a complete "constructor syntax" that can be used instead.
For example:
sys_days NewYears = y/1/1;
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
can be replaced by:
sys_days NewYears = year_month_day{y, month{1}, day{1}};
sys_days first_wd = year_month_weekday{y, month{1}, weekday_indexed{wd, 1}};
sys_days last_wd = year_month_weekday_last{y, month{12}, weekday_last{wd}};
I know this question has been asked a few times, and I'm asking again because I've got issues with existing solutions on SO.
My goal is to find number of days between 1900-01-01 and a given date. The date will be in the format as yyyy-mm-dd and the type is std::string.
The solution I've followed is https://stackoverflow.com/a/14219008/2633803
And below is my version:
std::string numberOfDaysSince1900v2(std::string aDate)
{
string year, month, day;
year = aDate.substr(0, 4);
month = aDate.substr(5, 2);
day = aDate.substr(8, 2);
struct std::tm a = { 0,0,0,1,1,100 }; /* Jan 1, 2000 */
struct std::tm b = { 0,0,0,std::stoi(day),std::stoi(month),std::stoi(year) - 1900 };
std::time_t x = std::mktime(&a);
std::time_t y = std::mktime(&b);
double difference;
if (x != (std::time_t)(-1) && y != (std::time_t)(-1))
{
difference = std::difftime(y, x) / (60 * 60 * 24) + 36526; //36526 is number of days between 1900-01-01 and 2000-01-01
}
return std::to_string(difference);
}
It worked fine until the given date comes to 2019-01-29 and 2019-02-01. In both cases, the output is 43494. And for the whole Feb, the output is 3 days less than expected. Then, when it comes to March 2019, the output is back to normal again.
Another case is 2019-09-03, the output is 43710, whilst the expected output is 43711.
Why would this happen to these specific dates? I ran the solution step by step and closely watched the variables in the memory but couldn't explain it.
Any suggestion is appreciated. Thanks.
The month should be represented as an integer between 0 and 11, not 1 and 12.
So
struct std::tm a = { 0,0,0,1,0,100 }; /* Jan 1, 2000 */
struct std::tm b = { 0,0,0,std::stoi(day),std::stoi(month)-1,std::stoi(year) - 1900 };
I would say there are other problems with your code. You cannot reliably initialise a tm like that (the order of fields within the struct is not guaranteed). Neither does difftime necessarily return a number of seconds (which you are assuming).
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)
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 = ...
I was trying to make a program that calculated the fee of a membership at a swimming pool. The user would enter a date (the last time a member renewed the membership), and the program would calculate if their membership was overdue or not, using the current date.
The membership is meant to be overdue a week (or another arbitrary time period) before the start of the month they joined in a year's time. For example, if I joined in February 2016, I would have to pay on January 24 2017 or before to make sure the membership is overdue. As soon as it gets to January 25, a month fee should be charged ($15) and as soon as it reaches February 25, two months fee should be charged etc.
However, I do not know how to charge for subsequent months after the first one. For example, paying on February 3 should result in one month overdue but paying on February 26 should be two months but I do not know how to do this.
How can I fix my function because it doesn't seem to work?
E.g. I entered November 15 2016 and it should return 15 since the membership was due on October 24 2017 but it returns 0.
int membershipFine(int joinDay, int joinMonth, int joinYear, int currentDay, int currentMonth, int currentYear)
{
int dueDay[12] = {25, 22, 25, 24, 25, 24, 25, 25, 24, 25, 24, 25}; // the week before the end of each month in days
int correspondingMonth = joinMonth - 2; // finds the element position that corresponds
if (correspondingMonth == -1) // if they joined in january, the array will go to december
{
correspondingMonth = 11;
}
int differenceInMonths = currentMonth - joinMonth + 12 * (currentYear - joinYear);
if (differenceInMonths < 11)
{
return 0;
}
else if ((differenceInMonths == 11) && (joinDay < dueDay[correspondingMonth]))
{
return 0;
}
else if (differenceInMonths == 11)
{
return 15;
}
if (differenceInMonths > 11 && joinDay < dueDay[correspondingMonth]) // not sure about this if and else statement
{
return (differenceInMonths - 11) * 15;
}
else return (differenceInMonths - 10) * 15;
}
The best way to deal with dates and times is to use a library that raises the level of abstraction about integers, to dates and times. Howard Hinnant's free, open-source, header-only library is such a tool.
It has a {year, month, day} class called date::year_month_day that lends itself to year and month arithmetic. One could use this to change the API of membershipFine from taking 6 type-unsafe parameters to just two type-safe parameters:
int
membershipFine(date::year_month_day joinDate, date::year_month_day currentDate);
Your description of the due date appears to say that it is independent of the day of the month of the join date, and that it is 1 year, less 1 week from the first of the month of the join date. If this is true, this can be easily computed like this:
using namespace date;
year_month_day dueDate{
local_days{(joinDate.year()/joinDate.month() + years{1})/1} - weeks{1}};
The expression joinDate.year()/joinDate.month() creates a year_month object, which is just a year and month, neglecting the day-of-the-month from joinDate. I add 1 year to that year_month, which results in another year_month, exactly 1 year later.
To that sum, /1 is appended. This creates a year_month_day corresponding to the first day of the month of the aforementioned year_month.
Now even though year_month_day is great for year and month oriented arithmetic, it is not so great for day and week-oriented arithmetic. The best data structure for that is a {count-of-days} from some epoch. This library has such a data structure called local_days. So I convert to that, subtract 1 week, and then convert back to year_month_day.
All of this (to compute the due date) happens in the lines of code above.
Now I need to compute the fine based on the relationship between currentDate and dueDate. The fine is $0 if currentDate < dueDate, and otherwise is a function of the number of whole months (plus 1) currentDate is beyond dueDate (as I understand your problem statement):
int fine = 0;
if (currentDate >= dueDate)
{
auto differenceInMonths = currentDate.year()/currentDate.month() -
dueDate.year()/dueDate.month();
if (currentDate.day() >= dueDate.day())
++differenceInMonths;
fine = differenceInMonths.count() * 15;
}
The difference in months, neglecting the day-of-the-month, can be computed by converting to year_month objects and subtracting. Now if currentDate.day() < dueDate.day(), this is the correct answer. For example if the difference in months is 1, but the day of the month in currentDate has not yet exceeded the day of the month in dueDate, then we don't want to charge for a second month, else we do. If we do, differenceInMonths is incremented.
Then the fine is simply the differenceInMonths, converted from months to integral, times 15.
<aside> If there are any <chrono> fans out there, the type of differenceInMonths is actually a std::chrono::duration with a period that is exactly the average month. Thus the .count() member function to access the underlying integral value.
I've added some print statements to the above code, and below I show the whole thing put together plus a driver with a few examples:
#include "date/date.h"
#include <iostream>
int
membershipFine(date::year_month_day joinDate, date::year_month_day currentDate)
{
using namespace date;
year_month_day dueDate{
local_days{(joinDate.year()/joinDate.month() + years{1})/1} - weeks{1}};
int fine = 0;
if (currentDate >= dueDate)
{
auto differenceInMonths = currentDate.year()/currentDate.month() -
dueDate.year()/dueDate.month();
if (currentDate.day() >= dueDate.day())
++differenceInMonths;
fine = differenceInMonths.count() * 15;
}
std::cout << "join Date is " << joinDate << '\n';
std::cout << "due Date is " << dueDate << '\n';
std::cout << "current Date is " << currentDate << '\n';
std::cout << "fine is $" << fine << '\n';
return fine;
}
int
main()
{
using namespace date::literals;
std::cout << membershipFine(feb/29/2016, jan/24/2017) << '\n';
std::cout << membershipFine(feb/29/2016, jan/25/2017) << '\n';
std::cout << membershipFine(feb/29/2016, feb/24/2017) << '\n';
std::cout << membershipFine(feb/29/2016, feb/25/2017) << '\n';
}
This outputs:
join Date is 2016-02-29
due Date is 2017-01-25
current Date is 2017-01-24
fine is $0
0
join Date is 2016-02-29
due Date is 2017-01-25
current Date is 2017-01-25
fine is $15
15
join Date is 2016-02-29
due Date is 2017-01-25
current Date is 2017-02-24
fine is $15
15
join Date is 2016-02-29
due Date is 2017-01-25
current Date is 2017-02-25
fine is $30
30
In summary, the use of a library such as this frees you from having to think in terms of ints so you can concentrate on the logic you have to implement in terms of dates and calendars. The result is compact and readable code that is far more likely to be correct.
Update
In the comments below the OP asks about how to parse a date from cin and how to get the current date. There are several options.
Here is how I recommend asking for a date:
date::year_month_day join;
while (true)
{
std::cout << "Enter join date as yyyy-mm-dd: ";
std::cin >> date::parse("%F", join);
if (!std::cin.fail())
break;
std::cin.clear();
std::string garbage;
std::getline(std::cin, garbage);
std::cout << "Please try again.\n";
}
If you prefer to ask for some other format, here is the complete list of parsing flags available for use.
And the OP asks how to get the current date. There are multiple answers. If you are content with the current date in UTC, that is the simplest:
using namespace std::chrono;
using namespace date;
year_month_day today = floor<days>(system_clock::now());
If you want the current date in your local time zone, you need to use "date/tz.h" (requires some installation) and this syntax:
year_month_day today{floor<days>(make_zoned(current_zone(),
system_clock::now()).get_local_time())};
If you want the current date in some time zone other than your current local time zone, that can be done with:
year_month_day today{floor<days>(make_zoned("America/Los_Angeles",
system_clock::now()).get_local_time())};
No matter how you parse your join and today, they can be used like this:
std::cout << membershipFine(join, today) << '\n';
In order that a device (with limited memory) is able to manage its own timezone and daylight savings, I'm trying to calculate daylight savings triggers for 85 time zones based on a simplified description of each timezone. I have access to minimal C and C++ libraries within the device. The format of the timezone (inc. DST) description for each time zone is as follows:
UTC - the base time and date from system clock
GMTOffsetMinutes - offset from GMT with DST inactive
DSTDeltaMinutes - modifier to above with DST active (as applicable to TZ)
DSTStartMonth - month in which DST becomes active
DSTStartNthOccurranceOfDay - the nth occurrence of the day name in month
DSTDayOfWeek - Sun = 0 through to Sat = 6
DSTStartHour - hour at which DST becomes active
DSTStartMinute - minute at which DST becomes active
and corresponding EndMonth, EndNth..., EndHour, EndMinute
I have found numerous examples going the other way, i.e. starting with the date, but they involve using the modulus, keeping the remainder and dropping the quotient hence I have been unable to transpose the formula to suit my needs.
I also tried to reuse the standard "Jan = 6, Feb = 2, Mar = 2, Apr = 5, May = 0, etc. modifier table and year modifiers from the "tell me what day the 25th of June, 2067 is?" party trick and developed the following algorithm.
Date = DayOfWeek + ((NthOccuranceOfDay - 1) x 7 ) - MonthCode - YearCode
This worked for the first 6 random test dates I selected but then I started to see dates for which it failed. Is it possible that the basic algorithm is sound but I'm missing a further modifier or maybe that I'm applying the modifiers incorrectly?
Is there another solution I could utilize?
Using this open source, cross platform date library, one can write:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
year_month_day us_daylight_starts = sys_days(sun[2]/mar/2015);
year_month_day us_daylight_ends = sys_days(sun[1]/nov/2015);
std::cout << us_daylight_starts << '\n';
std::cout << us_daylight_ends << '\n';
}
which will output:
2015-03-08
2015-11-01
The formulas this library is based on are in the public domain and documented here.
The algorithms paper has very complete unit tests validating the date algorithms over a range of millions of years (a far larger range than is necessary).
Sometimes daylight savings rules are written in terms of the last weekday of a month. That is just as easily handled:
year_month_day ymd = sys_days(sun[last]/nov/2015);
std::cout << ymd << '\n'; // 2015-11-29
That formula will be off by one week (or even two weeks) if MonthCode + YearCode is greater than or equal to DayOfWeek, because in that case you will be counting NthOccurenceOfDay from a negative date.
As an alternative, with no tables, you can compute the day of week of the first of the month using, for example, Zeller's algorithm:
int NthOccurrence(int year, int month, int n, int dayOfWeek) {
// year is the current year (eg. 2015)
// month is the target month (January == 1...December == 12)
// Finds the date of the nth dayOfWeek (Sun == 0...Sat == 6)
// Adjust month and year
if (month < 3) { --year, month += 12; }
// The gregorian calendar is a 400-year cycle
year = year % 400;
// There are no leap years in years 100, 200 and 300 of the cycle.
int century = year / 100;
int leaps = year / 4 - century;
// A normal year is 52 weeks and 1 day, so the calendar advances one day.
// In a leap year, it advances two days.
int advances = year + leaps;
// This is either magic or carefully contrived,
// depending on how you look at it:
int month_offset = (13 * (month + 1)) / 5;
// From which, we can compute the day of week of the first of the month:
int first = (month_offset + advances) % 7;
// If the dayOfWeek we're looking for is at least the day we just
// computed, we just add the difference. Otherwise, we need to add 7.
// Then we just add the desired number of weeks.
int offset = dayOfWeek - first;
if (offset < 0) offset += 7;
return 1 + offset + (n - 1) * 7;
}