Fixing the Date Class increment (C++) - c++

I have made a Library system. But I just checked and my 'Date' is not working properly.
The primary task of this class
(1) Increment date
Now, I am having an issue in the increment date, it works fine when I am incrementing it to the values up to 25-30. But when I enter 90, it messes up.
void increment_date(int num)
{
int day;
int month_new;
setDay(getDay()+num);
if( getDay()>Days_per_Month[getMonth()] )
{
day=getDay()-Days_per_Month[getMonth()];
setDay(day);
setMonth(getMonth()+1);
if(Days_per_Month[getMonth()]>12)
{
month_new=1;
setMonth(month_new);
setYear(getYear()+1);
}
}
cout<<"Return Date: ";
Print_Date();
}
//the code below is outside the class.
const int Date:: Days_per_Month[13]={0,31,28,31,30,31,30,31, 31, 30, 31, 30, 31};
int Date::checkDay(int testday) //returntype classname :: funcname (parameteres)
{
//static const int Days_per_Month[13]={0,31,28,31,30,31,30,31, 31, 30, 31, 30, 31};
if(testday > 0 && testday <= Days_per_Month[Month])
return testday;
if ( Month==2 && testday==29 && (Year%400==0 || (Year%4==0 && Year%100!=0)) ) //for leap year
return testday;
cout<<"Day "<<testday<<" invalid. Set to day 1."<<endl;
return 1;
}
enter image description here

setDay(getDay()+num);
if( getDay()>Days_per_Month[getMonth()] )
{
day=getDay()-Days_per_Month[getMonth()];
setDay(day);
setMonth(getMonth()+1);
In the above code, you add num to the value returned by getDay(), and then you check to see if getDay() is greater than the number of days in the current month, and if it is, you try to correct the problem by subtracting the number of days in the current month, and then incrementing the month.
So far, so good, but what if getDay() is still greater than the number of days in the current month after you've done that subtraction? (e.g. what if the user enters 300 for the increment-count?) In that case, you need to do the whole thing again, and keep doing it until getDay() is small enough to be a valid day-within-the-month value. So really a while loop is called for, not just an if.

Related

Checking a date is in an interval given by partial/periodic dates

I can define an interval with start and end in the format YYMMDD, but they can also be partial/periodic - meaning some elements (day, month or year) can be left blank.
For example, start = " 1115" and end = " 0115" the interval is 15th nov to 15th jan every year.
I want to check if a non-partial date is in the interval.
int compareParial(const char* first, const char* second)
{
for (int i = 0; i < 6; ++i)
{
if (first[i] != ' ' && second[i] != ' ' && first[i] != second[i])
return first[i] > second[i] ? 1 : -1;
}
return 0;
}
bool isDateInInterval(const char* start, const char* end, const char* searchDate)
{
int firstCompare = compareParial(start, searchDate);
int endCompare = compareParial(end, searchDate);
if (firstCompare <= 0 && endCompare >= 0)
return true;
// the date can still be in the interval if the start of the interval is in one year, but end in the next year
bool switched = 0 < compareParial(start, end);
if (switched && (firstCompare <= 0) != (endCompare >= 0))
return true;
return false;
}
int main()
{
cout << boolalpha << isDateInInterval(" 1115", " 0115", "251110") << endl;
return 0;
}
Update: If the dates are reversed check again if searchDate is in.
A problem I notice is what if start and end are reversed but the year is provided. For example: isDateInInterval("200105", "190601", "251110") would be true
C++20 contains types which can represent partial dates: year, month, day, year_month, month_day, etc.2
For example:
auto start = November/15;
auto end = January/15;
By using actual calendrical types, as opposed to strings, the logic you have to deal with can be greatly simplified. A complete year_month_day might be compared against an interval defined by a pair of month_day like this:
bool
compare_partial(std::chrono::month_day start, std::chrono::month_day end,
std::chrono::year_month_day searchDate)
{
using namespace std::chrono;
// Guess that both start and end fall in the same year
auto trial_start = start/searchDate.year();
auto trial_end = end/searchDate.year();
if (trial_start <= trial_end)
{
return trial_start <= searchDate && searchDate <= trial_end;
}
// start/y > end/y
// Otherwise guess that searchDate comes after trail_start:
if (trial_start <= searchDate)
{
// trial_end must be in the next year
trial_end += years{1};
return trial_start <= searchDate && searchDate <= trial_end;
}
// Otherwise searchDate < start/y && start/y > end/y
// trial_start must be in the previous year
trial_start -= years{1};
return trial_start <= searchDate && searchDate <= trial_end;
}
Be forewarned that even this answer is somewhat wrong1. However by using actual calendrical types to do things like add/subtract a year, and do the comparisons, one makes the code cleaner, easier to read, and thus less likely to contain errors.
This answer also only addresses the month_day partial date. You might also have a year_month partial date, or a mixture of month_day and year_month.
std::chrono has no type year_day, and I'm not sure what that would mean anyway. If you have an idea of what it would mean, I have no doubt that C++20 chrono could help you model it.
In any event:
cout << boolalpha << compare_partial(November/15, January/15, 2025y/November/10) << endl;
will output:
false
Even if you don't use C++20 chrono (or it's free preview), modeling this using calendrical types (perhaps of your own making), as opposed to strings, is highly recommended for creating a robust, error-free solution.
1 Expressions such as trial_end += years{1}; aren't guaranteed to be valid dates. For example what if trial_end has the value 2020-02-29. Adding a year to that will give you 2021-02-29. To make this correct, you must decide how you want to handle such situations (e.g. map it to 2021-02-28?).
2 There also exists a free, open-source, header-only preview of this part of C++20 which works with C++11/14/17: https://github.com/HowardHinnant/date
If year is set, and the dates are switched, you must return false, since it is an empty interval.
bool switched = 0 < compareParial(start, end);
if (start[0]==' ' && switched && (firstCompare <= 0) != (endCompare >= 0))
return true;
return false;

C++ If-else Branch wont produce an output

hope all is well. I was working on some code (C++) that would determine the season depending on the users input. The user is meant to type in a valid month and date in a year and from that the code is supposed to determine the season. Per instructions provided by my professor:
The dates for each season are:
Spring: March 20 - June 20
Summer: June 21 - September 21
Autumn: September 22 - December 20
Winter: December 21 - March 19
I was working on Spring for now, and this is the code I have. Just a little heads up, when inputting values March 20 - March 31, the code runs to my expectation and prints what is being looked for. However, when I type in any value such as June 1 - June 20 the program compiles, but it does not produce an output.
Here is the link to my code: https://repl.it/repls/FlippantAgileTheory
And here is the code:
using namespace std;
int main() {
string inputMonth;
int inputDay;
cin >> inputMonth;
cin >> inputDay;
if (inputMonth == "March" || inputMonth == "June") {
if (inputMonth == "March") {
if (inputDay > 19 && inputDay < 32) {
cout << "Spring\n";
}
else if (inputMonth == "June") {
// this is the aspect of the code that doesn't work
if ((inputDay > 0) && (inputDay < 21)) {
cout << "Spring\n";
}
}
}
}
}
The probable reason why good code needs to be well indented.
You can easily debug it if you indent it properly
Like-
if(inputMonth=="March"){
...
}
else if(inputMonth=="June"){
...
}
Also I think it would be better to use switch-cases here for the months differently other than using nested if-else statements that much, use the month names in an enum class for better code quality.
The problem becomes obvious if you add proper formatting.
All your print statements are within the block
if (inputMonth == "March") {
// ...
}
That means that no other month can cause any printing.
You probably meant
if (inputMonth == "March") {
// ...
}
else if (inputMonth == "June") {
// ...
}
It's important to make sure the code is properly formatted.
In your case, I assume what you meant to implement is:
if (inputMonth == "March" || inputMonth == "June"){
if (input == "March") {
if (inputDay > 19 && inputDay < 32){
cout << "Spring\n";
}
}
else if (input == "June") {
if ((inputDay > 0) && (inputDay < 21)){
cout << "Spring\n";
}
}
}
Just making changes to your brackets placement to make sure your if and else match properly will get the code working in no time.
I hope this helps.

Changing date for certain amount of days function

In class where we learn C++, I was given an assignment to make a class "date". Now, there is a specific function that I am required to make but I really do not have idea how to approach this. Members of class are day, month and year. Function takes some integer that represents days, and is supposed to set a new date, that comes after that many days. For example, if date is (DD-MM-YY) 20.01.2015, and we pass as an argument 15, new date is 04.02.2015, the problem is that I have to consider how many days each month has(considering February has 28 days), and if argument is too big, that we pass into next year, create an exception that prints how many days are there until next year(considering year has 365 days). That is, if the date is 20.12.2010, and argument is greater than 11, it should print 11.
My attempt was using while, where I declared at the beginning that int k=0; and where argument of function is a, than I used while(k!=a), but body of the function got really confusing because I used just too many if conditions. Another thing that I tried is to overlap operator++ and that surely gives me simpler function, because than there is only one for loop inside it, but I am not solving the problem, because in that overlapped operator function I am still using many if conditions.
Is there some elegant way to do this? Code and explanation would be great! Thank you!
Simply identify what you need and then create it, like
static unsigned int Date::days_of_month(const Month month, const unsigned int year);
void Date::operator+=(const unsigned int days);
+= could look like
void Date::operator+=(const unsigned int days){
increase current day by days
check if current day too large
if so, increase month (and maybe year)
repeat until day legal
}
Concept is clear? Haven't build in your output on purpose to give you something to do, after all, it's an exercise. Also wrote this in pseudo-code on purpose for the same reason. Try to create some code and if you really can't proceed, I'll add actual code.
const int m_daysInMonth[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; // first for index offset (no "zero" month)
class date {
public:
int days=20, month=11, year=2012;
void addDays(int daysNum)
{
int n_days = days, n_month = month; //new result. not saved, if there is an exception
while (daysNum > 0)
{
int daysToNextMonth = m_daysInMonth[n_month] - n_days + 1; //days before needs to change motn index
if (daysToNextMonth < daysNum) // change month
{
daysNum -= daysToNextMonth;
n_month++;
if (n_month > 12)
{
int daysLeft = m_daysInMonth[month] - days ;
n_month = month + 1;
while (n_month <= 12)
{
daysLeft += m_daysInMonth[n_month];
n_month++;
}
throw daysLeft;
}
n_days = 1; // start of the month
}
else // set day in the month
{
n_days += daysNum;
daysNum = 0;
}
}
days = n_days;
month = n_month;
}
};

Nested If dilemma

I am having troubles understanding this issue. The code is really basic but it behaves rather unexpectedly. The code is the simplified version of a routine to extract and save to a separate file the data for the day 15 of each month out of a daily database. Where is the problem ? The first cout prints the number of any day the outer if is entered. Then there are some conditional lines to select the right day ( not really important in this example ) and then there is the block, the inner if, that should print the data for the day 15 to the new file. Now, as you can see, while the outer loop ( attention ! ) is entered only on the 10th ( and this is already wrong - it should have written all the numbers from 11 to 15 ) but then it also prints that the file is written on the 15 ! Where is the problem ? The OUTER IF was entered only on the 10th, how can be the INNER IF be execute on the 15th ????
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
string newdata="mamma";
string risultato="-";
string PriorLine="-";
int PriorDay=0;
int lastmonth=0;
// Loops through all the months
for (int mese=1; mese <=12; mese++)
{
//Loops through all the days in the month
for(int day=1; day<=30; day++)
{
// at the month's beginning these 2 strings are set ="-"
if (mese != lastmonth)
{
risultato="-";
PriorLine="-";
}
// if we are between the 10th and the 20th and the result is still to be found
if (day>=10 && day<=20 && risultato=="-")
{
cout << day << endl; // LISTS ALL THE DAYS THIS LOOP IS ENTERED
if (day=15) // if it is exactly day 15 print that day's result
risultato=newdata;
// if that month in the data there is no day 15 and
// this is the second pass, choose the closest !
if (day>15 && PriorLine !="-")
{
if (abs(day-15)<=abs(15-PriorDay))
risultato=newdata;
else
risultato=PriorLine;
}
PriorLine=newdata;
PriorDay=day;
if (risultato != "-")
{
// writes the result ( risultato ) in a file
cout << "file written on the " << day << endl;
}
}
lastmonth=mese;
}
}
system("pause");
return 0;
}
if (day=15) assigns 15 to day and returns true. You need if (day==15)
When I simply compiled your code with g++ -Wall I got a warning:
error: suggest parentheses around assignment used as truth value
On this line:
if (day=15) // if it is exactly day 15 print that day's result
I'm willing to be the compiler has told you what your problem is. I suggest you enable all warnings in your build system.

Passing Private Variables in Classes - Why Is This Not Allowed?

I have this class:
class Date
{
public:
Date(); // Sets a date of January 1, 2000
Date(int mm, int dd, int yyyy); // Sets a date with the passed arguments; automatically converts two-digit years as being AFTER the year 2000
Date after_period_of ( int days ) const; // Elapses an arbitrary amount of time, and returns a new date
string mmddyy () const; // Returns date in MM/DD/YY format (1/1/00)
string full_date () const; // Returns date in full format (January 1, 2000)
string month_name () const; // Returns the name of the month as a string;
private:
int days_in_february(int yr);
int month;
int day;
int year;
};
When I try to pass private variable year as an argument into days_in_february, I get the following error message:
passing ‘const Date’ as ‘this’ argument of ‘int Date::days_in_february(int)’ discards qualifiers
days_in_february is called in after_period_of, like this:
Date Date::after_period_of (int days_elapsed) const
{
int new_month;
int new_year = year; // tried copying 'year' to get around this issue, but it did not help
int days_into_new_month;
int max_days_in_month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } ;
max_days_in_month[1] = days_in_february(new_year);
and again in the same function:
if (new_month == 13)
{
new_month = 1;
new_year += 1;
max_days_in_month[1] = days_in_february(new_year);
}
days_in_february simply returns the number 28 or 29 based on year that is passed into it. It does not attempt to manipulate anything outside of its own block.
I have even tried to pass a non-programmed variable into it (days_in_february(2000)) and I get the same error.I've tried moving that function into the public domain, but that didn't fix the issue either.
Why is this happening?
Why am I not allowed to do this?
Inside after_period_of, you cannot access non-constant functions; in particular, you cannot access days_in_february. You can fix this by also declaring the latter function const.