I need some help learning C++

I’m doing a programming course and they are teaching c++. I have an assignment I’m working on and I’m really stuck.

I legitimately don’t know how to do what they are asking and I’m hoping for some help.

I can’t copy other peoples work but I’m hoping for some tips/guidance.

I have to write a program where someone can add or subtract days of a date that they input in day, month, year. And it has to output the date dd/mm/yyyy that it would be after the addition or subtraction. The amount added or subtracted also has to be something that can be imputed.

I’ve googled this but a lot of people seem to be using libraries and things which I haven’t been taught yet and the assignment is supposed to be done using what I’ve been taught so far which is integers, if and else statements.

Treat the date as a string, and parse it.

First, determine a valid date format. Either your assignment already decides what is valid, or you get to pick your own. I will assume “yyyy mm dd” as the date, here.

Second, work with cin streams. What you can do relatively simple is;

int year, month, day;

std::cin >> year >> month >> day;

Now you will have year, month, day in integers. Good luck with the rest!

Hey thanks for that. Thankfully the integer part I have figured out. That I understand. The part I’m stuck on is how to code the addition/subtraction calculations and have it output correctly.

Most programs follow a very similar pattern.
serialized data is input → Data is Parsed into internal data structures → data is encoded into serialized format

Int this case the serialized input and output is a string to stdout I assume?

You should start off with some classes to model the problem and the internal structure. You want these classes to represent data and not logic so avoid putting a bunch of methods in it or complicated logic. You will want to have a Class for the month, day, and year. Start with month. Not as familiar with C++ but try and create a class for each month Jan, Feb, March, … and make them accessible with a static accessor. It will be similar to the singleton pattern but 12 instances instead.

The Day class will just have a int to represent the day. Now the problem is it’s invalid to have a 40th day of a month and so on. So you need a Day class as an abstract class and two classes that inherit from it. One will just be called InvalidDay and the other will be ValidDay. Create a static method on the abstract class that takes an int that returns a “Day” type. If it’s some day that doesn’t exist with any of the months than return a InvalidDay instance.

Make another data class for year with the same pattern but less restrictions. A negative year is obviously invalid.

Now you need to make another class because not all months have the same amount of Days so call it MonthDay. MonthDay has two values, with the types Day and Month. Similar pattern as before with an invalid MonthDay type and a Valid one. Static method on MonthDay abstract class will take a Day and Month. The return type will be a MonthDay.

Then finally you need a MonthDay and a Year type in one final class called just Date. Date just needs a MonthDay and a Year values.

This will represent you internal domain model. Now you should create a class called DateAlgebra or DateAdder. Different ways to do this is but add a method to it to called addDate that takes an argument of Date, amount to add to the day, the month, and the year.

How is the user entering this information?

1 Like

Essentially you need a map that points from month to the last day of the month. Add the days to the current days and check if it’s greater than that. If its greater than increment the month by 1 and subtract the days by the last day. Then run this check again to make sure its not jumping by more than one month.

std::chrono is the “standard way” of doing time based stuff in c++ Date and time utilities - cppreference.com

There’s a year_month_day type.

If you look at the page for year month day it says

An implicit conversion to and from std::chrono::sys_days allows std::chrono::days-oriented arithmetic to be performed efficiently.

So, they’re you go.


There’s a specific problem/trap when dealing with dates/days in particular. Not all days have the same length in all timezones. Converting to/from Unix timestamps and then doing +/- 86400*days is not the way to do it. Also there’s the obvious leap year February stuff, etc.

1 Like

The logic is simple;

  1. Input date
  2. Input number of days to offset
  3. Calculate proper date
  4. Print date

Now, let’s think about #3 for a bit. We have a bit of a problem:

  • There are 12 months with a variable number of dates between 28-31 days
  • Every 4th year, February has 29 days
  • … Except every 100th year, it doesn’t…
  • Except every 400th year, it does

So, what to do here? Well, we can move to a more predictable domain. How about we count the number of days since a certain point in time? A day is specified as 24 hours, come rain or sunshine. This does solve our arithmetic woes, since “50 days before today” is a valid arithmetic input.

It does very little for the gregorian calendar though. To solve our date woes, we need to keep track of how many leap years exist between our offsets. Here are a few tests for a function:

// Prototype function, this is what you should implement
std::string find_date(int year, int month, int date, int offset);

assert find_date(2000, 1, 1, 20) == "2000-01-21";
assert find_date(2000, 1, 1, 60) == "2000-03-01";
assert find_date(1900, 1, 1, 20) == "1900-01-21";
assert find_date(2000, 1, 1, 60) == "1900-03-02";
assert find_date(408, 5, 1, 20) == "408-05-21";
assert find_date(407, 12, 1, 100) == "408-03-11";
assert find_date(5000, 1, 1, 3000) == "5008-04-09";

As you can see, it’s a major headache, that’s why I just recommend you learn to deal with UNIX timestamps and the libraries already developed here.

1 Like

Yes!

The concept of days and calendars is a civil/political thing, not a scientific thing. E.g. Dec 20 2011 + 20 days in Samoa should correctly yield a different date than Dec 20 2011 + 20 days in NYC.

Not something you want to mess with. Be happy the libraries exist.

The thing is guys this is a graded assignment that I have to write from scratch only using what I have been taught so far and we have only just started on libraries.

The program output has to input based like this

Write a C++ program that does the following:

a) input a number of days from -7 to 7. This value is called the difference .

b) input a date as day month year

c) display the date that is different days from the input date

Example 1:

Enter the difference in days: 2

Enter a date in the form day month year: 14 5 2019

The final date is: 16/5/2019

Example 2:

Enter the difference in days: -3

Enter a date in the form day month year: 8 11 2020

The final date is: 5/11/2020

Example 3:

Enter the difference in days: 1

Enter a date in the form day month year: 31 12 2017

The final date is: 1/1/2018

Notes:

1. Your display should be similar to the examples above.

2. Assume that the date that is entered is a valid date (no need to check).

3. Assume that the difference that is entered is from -7 to 7 (no need to check).

4. You will need to check if the year is a leap year.

5. Remember to test your program with several different examples.

A possible approach:

1. Get the program working for positive differences and ignore February.

2. Modify the program to also work for negative differences and continue to ignore February.

3. Modify the program to include February.

It’s funny how when you sit at something for a while and try things you start to figure it out. Still got a lot to go but am getting it. I find the best research was going online and seeing peoples failed attempts and reserve engineering it to see how they got it wrong.

Only -7 to 7? THAT completely changes the ballpark. :slight_smile:

To handle month boundaries here is a neat little trick;

int month_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (leap_year(year)) {
    month_days[1] = 29;
}

Then just do:

days += offset; // Offset is the number of days you are changing

if (days >= 1 && days <= month_days[month]) {
    // We are done here
}

Now all you need to take care of are the edge cases :slight_smile: Hope that helps!

Hey that really helps a lot! The course I’m doing is great but they leave a lot to interpretation and me being a newbie and not really knowing what I can or can’t do I get a bit stuck. I even commented to them that between the course material and the assessment question it is like there is something missing between what they are teaching and what they are asking.

Either that or I really suck.

Are you able to use modern C++20 ? If so, there’s built in support for date operations. Start at Standard library header <chrono> - cppreference.com

I think so. Turns out I can use untaught ways to do it as long as I can show understanding of what the code is doing. That isn’t a problem as understanding code I’m seeing isn’t hard it is just knowing how to write it.

1 Like

What library is used for this if I may ask?

The leap_year() function?

This is just pseudo code, you can easily write your own function;

bool leap_year(int year) {
    // Returns false if:
    // year is not divisible by four
    // year is evenly divisible by 100, but not 400
    return true;
}

Bonus if you can do it within a single expression like this between function:

bool between(int lower, int x, int higher) {
    return (lower < x && higher > x);
}
1 Like

I was more meaning a for the month_year[ ] aspect.

I have noticed if you don’t include the right libraries sometimes things don’t always work so thought I’d ask.

month_days[] is simply an array that is defined by the right side of the assignment (equal sign), and is a feature of the language itself (no library required). Surprised you haven’t worked with this kind of thing yet.

To clarify, when writing this:

int my_array[] = { 1, 2, 3 };

It is equivalent to:

int my_array[3];
my_array[0] = 1;
my_array[1] = 2;
my_array[2] = 3;

Follow everyone else’s advice here, I’m sure nobody is steering you in the wrong direction BUT think about leap years.
Logically step though the how the process will change if someone wants to minus three days from march 1st or 3rd on a leap year. I lost some points on an exam not considering that.

1 Like

I don’t know why people are recommending the chrono package (other than that it’s normally better to use pre-existing code where possible in a production environment, but this isn’t that).

However, this is a simple introductory programming exercise, no sophisticated libraries required (or used!). I would expect a student to write the code, not call a library function, even though that would be the correct solution in a work environment.

This is a simple problem that’s mainly about dealing with limits and edge cases. You need to worry about leap years only if the month is February and you’re going forward possibly into March, or March and you’re possibly reversing into February. All the rest of the cases are crossing month and possibly year boundaries - in either direction - and ensuring you don’t create an incorrect date.

As wertigon points out above, all you really need is an array of integers which are the numbers of days in months. If the current year in the date read in is a leap year then February gets one added, and that’s only needed for the February-March transition in either direction.

Then you get your current date and add the positive or negative difference. If the value is greater than the current month number of days then subtract the current month days from the total and add one to the month. If the month goes across the year boundary then reset the month to 1 and add one to the year. Do similar in reverse: if less than 1 then subtract one from the month, ensuring that if you wrap around from January to December that you also decrement the year. Whatever 0 or negative value you got from the day calculation add to the previous month, e.g.: subtracting 7 from Jan 7th 2022 gets you Dec 31st 2021.

What I’d be looking for in the solution is correctly handling edge cases: crossing month/year boundaries in either direction, and doing so with a minimum of tests, and avoiding out-by-1 errors. I’d prefer data-driven solutions rather than seeing a lot of if-then-else or switch statements, e.g.

The problem is mostly about limits and correctly calculating indices. The only other issue is the format and processing of the input, and that has been specified as 3 correctly validated date values. You said you have that part covered already. The instructor gave good approaches to getting working code: code is typically refined in a step-wise fashion: incrementally get functionality operating without having to change the overall structure or methodology (which typically means you incorrectly understood the initial problem, or started out too quickly without considering all the ramifications). However, that’s more about real-world code than programming exercises. Still, a good habit to get into is clearly defining the problem space and conceiving a solution that leaves room for maneuver as you get closer to the solution and inevitably discover nuances in the problem or the implementation of the solution, or - more likely - management changes what they’d like the program to do! But that’s a whole other kettle of fish.).

Good luck with the assignment!