# Given a date and a duration, calculate the future date

The question is basically like this: Given year, month, day and duration, calculate the future date based on given data and duration. The given date guarantees to be after 1900-01-01, and the duration k is between [0, 10000].

For example: Input: 2016 10 1 100(meaning given 2016-10-1, what is the future date after 100 days) Output: 2017-01-09

Another example: Input: 2017 1 1 10 Output: 2017-01-11

I have done my solution, but it is trivial and ugly. The most frustrating part is line 44 - 47, where I have to handle special cases on month and year. I feel like this special and trivial handling is due to my design of calculating month, but I cannot figure out a more universal/clear solution except for current solution.

Code with line indication and better format fyi : https://paste.ubuntu.com/24765263/

#include <iostream>
#include <string>
#include <unordered_map>
using namespace std; // I know global namespace is bad practice. Just to save time.

int getMonthDays(int y, int m){
unordered_map <int, int >daysMap = {{1,31}, {2,28}, {3,31}, {4,30}, {5,31}, {6,30}, {7,31}, {8,31}, {9,30}, {10,31}, {11,30}, {0,31}};
if (m == 2){
if (y % 400 ==0 || (y % 100 != 0&& y % 4 == 0)){
return 29;
}
else{
return 28;
}
}
else{
return daysMap[m];
}
}

int main (){

int year, month, day, duration;
cin >> year >> month >> day >> duration;

int res_year;
string res_month, res_day;

int days = getMonthDays(year, month) - day;
while ( days < duration ){
month++;
if(days + getMonthDays(year + month/12, (month - 12 * (month/13))% 12) > duration){
break;
}
else{
days += getMonthDays(year + month/12, (month - 12 * (month/13))% 12);
}

}

res_year = year + month / 12 ;
res_month = (month - 12 * (month/13))% 12 >= 10 ? to_string((month - 12 * (month/13))% 12) : "0" + to_string((month - 12 * (month/13))% 12);
if (res_month == "00"){
res_month = "12"; // dont have set month "12", so if get month as "00", convert it to "12"
res_year -= 1; // if the result month is "12", year minus 1 coz Month December is still in this year.
}

if (duration - days > 0 ){
if (duration - days >= 10){
res_day = to_string(duration - days);
}
else{
res_day = "0" + to_string(duration - days);
}
}
else{
res_day = to_string(day + duration);
}
cout << res_year << "-" << res_month << "-" << res_day;

}

• This is common interview type question. I think you choose the wrong technique to solve this. When doing date/time and manipulating: Convert to seconds (an epoch time). Do your manipulation then convert back into Gregorian from there. Jun 4, 2017 at 0:47
• @LokiAstari, I believe I found more or less C++ way of outputting result of std::chrono::xxx_clock::now(). It might be worth updating the answer you've given long ago if you think the approach is good. Jun 4, 2017 at 8:25
• For convenience you can also take a look at Hinnant's Date library to simplify the work for you. Jun 4, 2017 at 9:04
• @coincoin, I already mentioned it in the review :) I didn't want to deal with the license so I implemented some stuff by hand. Jun 4, 2017 at 9:32

This is quite tricky problem to get right. As Loki said, we need to convert it to seconds after epoch. But doing so is not trivial...

## Standard approach:

Well, not really standard, but in my opinion one should use std::chrono in this case. Some stuff is done in a roundabout way, but I don't think it is a huge problem. Howard Hinnant has written a library for it, but in case the license isn't acceptable, I'll reimplement some functionality by hand.

### output std::time_point:

The first issue is outputting a std::time_point. The problem with it is that it doesn't have operator<< overload for streams. The only way possible to deal with this is to implement our own:

The only ways to print time are either std::ctime() and std::put_time() (not counting the "implement by hand" approach). So let's follow the thread and find its end and test it:

#include <iostream>
#include <chrono>
#include <iomanip>

template <typename Clock, typename Duration>
std::ostream& operator<<(std::ostream& os, const std::chrono::time_point<Clock, Duration>& timep)
{
auto converted_timep = Clock::to_time_t(timep);
os << std::put_time(std::localtime(&converted_timep), "%Y %b %d %H:%M:%S");
return os;
}

int main()
{
auto now = std::chrono::system_clock::now();
std::cout << now;

return 0;
}


Output: 2017 Jun 04 12:07:48.

The only problem with implementation is that it can't be used from multiple threads, since std::localtime() returns pointer to static variable. The format could be mutable by some function, but I wouldn't care about it at this point.

Since we can manipulate std::chrono::time_point, and std::chrono::duration, let's use everything we have:

convert given date to std::chrono::time_point<system_clock>:

A good news, at last! From std::mktime():

Converts local calendar time to a time since epoch as a time_t object. time->tm_wday and time->tm_yday are ignored. The values in time are permitted to be outside their normal ranges.

Hooray! So we can just fill in the std::tm structure with year, month, and day since January 1 and we are done!

#include <iostream>
#include <chrono>
#include <iomanip>

template <typename Clock, typename Duration>
std::ostream& operator<<(std::ostream& os, const std::chrono::time_point<Clock, Duration>& timep)
{
auto converted_timep = Clock::to_time_t(timep);
os << std::put_time(std::localtime(&converted_timep), "%Y %b %d %H:%M:%S");
return os;
}

auto convert_to_timepoint(int years, int months, int days)
{
//perform checks, do division, modulus and stuff...
years -= 1900; //epoch
std::tm date = {};
date.tm_year = years;
date.tm_mon = months;
date.tm_mday = days;

return std::chrono::system_clock::from_time_t(std::mktime(&date));
}

int main()
{
auto now = std::chrono::system_clock::now();
std::cout << now << '\n';

std::cout << "calling convert_to_timepoint:\n";
auto date = convert_to_timepoint(1991, 0, 23);
std::cout << date;

return 0;
}


Output:

2017 Jun 04 13:08:49
calling convert_to_timepoint:
1991 Jan 23 00:00:00


Now the easy stuff, add the given number of days:

#include <iostream>
#include <chrono>
#include <iomanip>

template <typename Clock, typename Duration>
std::ostream& operator<<(std::ostream& os, const std::chrono::time_point<Clock, Duration>& timep)
{
auto converted_timep = Clock::to_time_t(timep);
os << std::put_time(std::localtime(&converted_timep), "%Y %b %d %H:%M:%S");
return os;
}

auto convert_to_timepoint(int years, int months, int days)
{
years -= 1900; //epoch
std::tm date = {};
date.tm_year = years;
date.tm_mon = months;
date.tm_mday = days;

return std::chrono::system_clock::from_time_t(std::mktime(&date));
}

template <typename Clock, typename Duration>
{
constexpr std::time_t seconds_in_day = 60 * 60 * 24;
//                                     mm   hh   dd

std::time_t days = seconds_in_day * days_to_add;
auto date = Clock::to_time_t(timepoint);
return Clock::from_time_t(date + days);
}

int main()
{
auto now = std::chrono::system_clock::now();
std::cout << now << '\n';

std::cout << "calling convert_to_timepoint with 1991 0 23 (1991 Jan 23):\n";
auto date = convert_to_timepoint(1991, 0, 23);
std::cout << date << '\n';

std::cout << "10 day later (1991 Feb 02):\n" << add_days(date, 10);

return 0;
}


Output:

2017 Jun 04 13:21:29
calling convert_to_timepoint with 1991 0 23 (1991 Jan 23):
1991 Jan 23 00:00:00
10 day later (1991 Feb 02):
1991 Feb 02 00:00:00


I left the convert_to_timepoint() so that it would be reusable on its own, but if needed it can be fused with add_days().

## Some thoughts:

• using namespace std; rarely buys anything, but opens a chance for errors.
• standard library has a solution most of the time
• modularity is important. Breaking functions into logical pieces makes it very easy to quickly prototype, adjust, mix'n'match.

## Conclusion:

In this kind of problem, it is very dangerous try to implement by hand, since there are lots of edge cases. As a result, the problem given was rather a test of knowledge of standard library.

• The date is calculated using this site. Jun 4, 2017 at 8:39
• Thank very much for your explanation! @Incomputable Really appreciated!! Jun 15, 2017 at 5:05
• @JenifferPan, you're welcome! It's still worth checking out Howard's library, since he was leading <chrono>s development. Jun 15, 2017 at 14:22