Understanding code for first day of month function - c++

I'm doing a practice exercise. It asks me to create a calendar of the month, year which is the current user time. I have looked up some code on the Internet, it works well, but I can't understand it clearly. Especially the line year -= month < 3. Can someone explain it, please?
//return the daycode of the first day of month.
int firstDayOfMonth(int month, int year) {
int dow = 0;
int day = 1;
int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
year -= month < 3; // I cannot understand this.
cout<<"This is year "<<year<<endl;
dow = ( year + year/4 - year/100 + year/400 + t[month-1] + day) % 7;
return dow;
}
int main()
{
int a;
cout<<firstDayOfMonth(2,2018)<<endl;
return 0;
}

In C++, boolean values can be implicitly converted to integers, with false becoming 0 and true becoming 1. (See bool to int conversion.)
So year -= month < 3; is equivalent to:
if (month < 3) {
year -= 1; // true -> 1
} else {
year -= 0; // false -> 0
}
which can be simplified to:
if (month < 3) {
--year;
}
The motivation is that January and February (months 1 and 2) come before any leap day, while the other months come after any leap day, so it's convenient to treat January and February as being at the end of the previous year, and let the leap day be added to the calculation for the entire March-to-February year.
This code is obviously not optimized for readability.

What that means is:
if the condition (month < 3) is true, then decrement by 1. if the condition (month < 3) is false, then decrement by 0 (year stays the same)
The value of 1 & 0 represent false & true of the month & number comparison.

Related

Cannot understand uncommon syntax [duplicate]

This question already has answers here:
bool to int conversion
(4 answers)
Closed 1 year ago.
I have recently come across a function which calculates the day of the week for any given date. The function is shown below.
unsigned int getDayOfWeek(const unsigned int day, const unsigned int month, unsigned int year)
{
static unsigned int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
year -= month < 3;
return ( year + year/4 - year/100 + year/400 + t[month-1] + day) % 7;
}
I am having trouble understanding the syntax of year -= month < 3. I am assuming it expands to year = year - (month < 3), however I still cannot understand what this does.
My question is: what does this syntax do in general, not just in the context of this function? For example a -= b < 3.
Thank you in advance.
month < 3 is a boolean expression.
false converts to 0
true converts to 1.
You might rewrite it as:
if (month < 3) { year = year - 1; }

Getting the day of the week a year starts at

I was making a function in C++ to get the day of the week given the day, month and year (from 1900 on). The way I have to do it (I'm following orders, it's an exercise) is with the modulus of 7 of the total of days passed.
For example, 21 November 2018 will be the 325th day of that year (Taking into account leap years). The day of the week will be 325 % 7, which will give a number between 0 and 6, 0 being Sunday, 1 being Monday and so on, until 6 which would be Saturday.
But this will only work in years that start on Monday. 2018 works, but 2019 will be off by 1 day, as it starts on Tuesday.
My idea of fixing this is by knowing on what day that year starts and adding it to the 0-6 number given (fixing it if it's higher than 6), but I'd have to use the function for the year before, which would do so until it reaches 1900, which would be set to Monday. It sounds terrible, and I can't figure out another way of doing it.
Thanks in advance
If you don't want to use any libraries and do it purely by calculation, here is a solution.
http://mathforum.org/dr.math/faq/faq.calendar.html (Web Archive page)
or a easy explanation video.
What you can do is convert this logic into your program and find out the day of the week.
int dayofweek(int d, int m, int y)
{
static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
y -= m < 3;
return ( y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
Code Source.
http://www.cplusplus.com/reference/ctime/tm/
http://www.cplusplus.com/reference/ctime/mktime/
int weakDayOfYearBegin(int year)
{
std::tm t {};
t.tm_year = year - 1900;
t.tm_mday = 1;
std::mktime(&t);
return t.tm_wday;
}
https://wandbox.org/permlink/1ZnByeurgMrEF3fA

Explain this leap year Function C++

I'm having an issue with this code,I do not understand how the function works. I need to validate the input from the user, to see if their date that they placed is valid. And if it isn't I set the error code. So in my read function I cin the date then validate the input and call mdays() however, for some reason I don't know how to check in my if statement in the read function if the date is validate or not.
int Date::mdays() const
{
int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1};
int mon = _mon >= 1 && _mon <= 12 ? _mon : 13;
mon--;
return days[mon] + int((mon == 1)*((_year % 4 == 0) &&
(_year % 100 != 0)) || (_year % 400 == 0));
}
The code is very clever, written by someone who wanted to demonstrate that they are smart. I hate clever code. (It's also quite slow, I hate code that tries to be clever and fails).
Remember the rules for leapyears:
Every fourth year is a leap year. Except that every 100th year is not a leap year. Except that every 400th year is a leap year.
Most months you can look up from a table, except that February has either 28 or 29 days. So to understand the code, what happens if the month is not February? And what happens if the month is February? mon will be equal to 1. What is the value of (mon == 1) in February? How would you express the rules for leap years?
And the function that you showed calculates the number of days in a month, it doesn't do any validation. Obviously you need to know that April has 30 days to know that April 31st is invalid.
You can change the signature of mdays(), return a boolean to indicate if the date is validate or not, and put an output argument to store the days if the date is validate
bool Date::mdays(int& month_days) const {
int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (_mon < 1 || _mon > 12) return false;
mon--;
month_days = days[mon] + int((mon == 1)*((_year % 4 == 0) && (_year % 100 != 0)) || (_year % 400 == 0));
return true;
}
If you can modify the Date class, you should be able to create new method utilizing return value of mdays() like this:
bool Date::validate_day_and_month() const {
int maxday = mdays();
if ( maxday < 0 ) { return false; } // mdays() = -1 if _month is bad
if ( _day <= 0 || _day > maxday ) { return false; }
return true;
}
Here, _day is the day part of the user date input.

Precedence & Arity in strange statement

What is the execution order and possible results of this statement: leap = year%4 == 0;
(The left part is assignment and the right assertion?)
Which is excerpt from the following algorithm used to calculate day of the week of any date in Gregorian calendar:
static char daytab[2][13] =
{
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
for (year = 1; year <= y; year++)
{
leap = year%4 == 0;
if (year%100 == 0 && year%400 != 0)
leap = 0;
for (month = 1; month <= m; month++)
{
d += daytab[leap][month - 1];
daystotal = 365*(year - 1) + (int)floor((year-1)/4)
- (int)floor((year - 1)/100) + (int)floor((year - 1)/400) + d;
}
}
Look here operator precendence. year % 4 will be evaluated, than result will be compared to 0 and then result will be assigned to leap variable.
year % 4 == 0 is equivalent to (year % 4) == 0, which takes the remainder after dividing year by 4, then compares that to 0 and produces a Boolean result--true or false. You don't show a declaration/definition of leap, so we can only guess at its type. If it's a bool, that result will be assigned directly to it. Based on the later code:
if (year%100 == 0 && year%400 != 0)
leap = 0;
It appears that leap is probably some other arithmetic type (probably int). This is quite common, especially in code that was originally written in C90, which has no Boolean type.
In this case, the bool will be converted before the assignment. When being converted to arithmetic types, false converts to 0 and true converts to 1 (going in the other direction, 0 converts to false, and any other value converts to true).
So, the code has basically the same effect as something like:
if ((year % 4) == 0)
leap = 1;
else
leap = 0;
...or:
leap = ((year % 4) == 0) ? 1 : 0;
If I were writing it, I think I'd probably write the code more like this:
if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0) )
leap = 1;
else
leap = 0;
...or (more likely) just:
leap = ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
At least to me, this more directly states the conditions of "what is a leap year" in the Gregorian calendar1. I suppose you could view the original code as a historical artifact through: it first computes whether it's a leap year under the rules of the older Julian calendar, then separately adds on the rules that were added in the Gregorian calendar. If somebody really wanted to reflect that history, however, they should probably include a comment explaining that that's why the code is written as it is. As it stands right now, rather than just computing the correct value, it starts by computing a value that may be incorrect, then checks for more conditions, and patches the value up afterward.
1. Which are, of course, something like: A year is a leap year if it is divisible by 4, and either not divisible by 100, or also divisible by 400. So, for example, 2000 was a leap year (divisible by 4 and also divisible by 400) but 1900 was not (divisible 4, but also divisible by 100 and not divisible by 400).

Date to Day of the week algorithm?

What is the algorithm that, given a day, month and year, returns a day of the week?
This can be done using the std::mktime and std::localtime functions. These functions are not just POSIX, they are mandated by the C++ Standard (C++03 ยง20.5).
#include <ctime>
std::tm time_in = { 0, 0, 0, // second, minute, hour
4, 9, 1984 - 1900 }; // 1-based day, 0-based month, year since 1900
std::time_t time_temp = std::mktime( & time_in );
// the return value from localtime is a static global - do not call
// this function from more than one thread!
std::tm const *time_out = std::localtime( & time_temp );
std::cout << "I was born on (Sunday = 0) D.O.W. " << time_out->tm_wday << '\n';
You need a starting point. Today is fine. Hard-code it.
Then, you need to represent the number of days in a month. This is 31, 28, 31, 30, 31, 30, ... . So you can start adding and subtracting 365 % 7 to the day of the week for each year, and (sum of days in difference of month) % 7 again. And so on.
The caveat: Leap years occur on every 4th year, but not every 100th, unless that year is also a multiple of 400.
One of the easiest algorithm for this is Tomohiko Sakamoto Algorithm:
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
Check this out: https://iq.opengenus.org/tomohiko-sakamoto-algorithm/
I found Wang's method also interesting
w = (d - d^(m) + y^ - y* + [y^/4 - y*/2] - 2( c mod 4)) mod 7
http://rmm.ludus-opuscula.org/PDF_Files/Wang_Day_5_8(3_2015)_high.pdf This pdf is really helpful too.
Thanks!