0

I have the following code, with which I get today's date. I would like to know if from this code I can obtain the date 6 and 12 months later. Or how can I get these dates?

Thank you!

#include <iostream>
#include <ctime>

using namespace std;

int main() {
    time_t hoy = time(0);
    char* fecha = ctime(&hoy);
    
    cout << "La fecha es: " << fecha << endl;
}

I try to make a program with which the user planned the fertilization period of certain plants, among other things, that is why I try to make the program print the date of the next 6 and 12 months, from today (well, from the day in which the user registers a plant). So far I have not succeeded. :(

phuclv
  • 37,963
  • 15
  • 156
  • 475

4 Answers4

1

Since it seems that you only need a rough approximation of the future date for your use-case, you can probably get by with simply assuming that every month has about 30.4 days in it, and calculating a number of seconds into the future based on that. You can then use ctime() to generate a new date-string for that future time:

#include <stdio.h>
#include <time.h>

int main(int argc, const char ** argv)
{
   const time_t now = time(NULL);

   // Assuming every month has ~30.4 days; that's not really true
   // but it's close enough for plant fertilization purposes, I think
   const time_t ROUGHLY_ONE_MONTH_IN_SECONDS = (30*24*60*60) + (10*60*60);

   for (int i=0; i<=12; i++)
   {
      const time_t then = (now+(i*ROUGHLY_ONE_MONTH_IN_SECONDS));
      printf("In %i months, the approximate date/time will be:  %s", i, ctime(&then));
   }

   return 0;
}

Note that for an exact answer you'd need to take the varying lengths of months into account, plus leap years and God-only-knows-what-else, and in that case you'd probably be better off using a modern date/time library instead.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
1

I would use struct tm and convert your time_t using gmtime.

Then you can add 6 or 12 to tm_mon (don't forget to handle the overflow by adding 1 to tm_year), and convert back to time_t with mktime

Vlad Feinstein
  • 10,960
  • 1
  • 12
  • 27
  • 1
    There is a case where you pass `Jan 31st`, you add 6 months to `Jun 31st` which does not exist. `mktime()` will then convert to `July 1st` which you have to push back to `Jun 30th`. –  Jan 07 '22 at 20:06
1

If you want 6 months from a given date, counting months and not days, the solution is to split the date and increment manually the months and years. Then you will have to adjust for year wrapping and month wrapping as well.

These functions are defined in C89/C99 so not specific to Posix.

The biggest advantage of this solution is that you don't have to link against any external library. It should be available with your compiler on Linux, Mac and even on Windows/MS Visual Studio.

#include <time.h>
#include <stdint.h>
#include <stdio.h>

time_t add_months( time_t from_date, uint32_t months ) {
    // Split date
    struct tm* tmptr = ::gmtime( &from_date );
    if ( tmptr == nullptr ) return 0;
    struct tm date = *tmptr;

    // Save original date
    struct tm org = date;

    // Add months/years
    uint32_t years = months/12;
    months = months % 12;
    date.tm_year += years;
    date.tm_mon += months;

    // Correct for year wrap
    if ( date.tm_mon>11 ) { 
        date.tm_mon -= 12;
        date.tm_year += 1;
    }

    // Convert back to time_t
    time_t dt = mktime( &date );

    // Check for end of month wrap
    // eg Jan/30 -> Mar/02 -> Feb/28
    if ( date.tm_mday != org.tm_mday ) {
        dt -= date.tm_mday * 86400;
    }
    return dt;
}

int main() {
    time_t now = time(nullptr);
    time_t later = add_months( now, 6 );

    struct tm* tmptr = ::gmtime( &now );
    if ( tmptr!=nullptr ) {
        printf( "Now: %s\n", asctime(tmptr));
    }
    tmptr = ::gmtime( &later );
    if ( tmptr!=nullptr ) {
        printf( "Later: %s\n", asctime(tmptr));
    }
}

Result:

Program stdout
Now: Thu Jan  6 01:47:07 2022
Later: Wed Jul  6 01:47:07 2022

Godbolt: https://godbolt.org/z/vE4xhsP3E

  • 1
    Wow. This works as I expected. Thank you all for your contributions! :D – Arturo García Flores Jan 07 '22 at 19:47
  • @ArturoGarcíaFlores double check this is the behaviour you expect for the end of month wrap - if you pass `Jan 30` and add one month, it will go to `Feb 30th` and `mktime()` will correct to `March 2nd`. Then you subtract 2 days to get back to `Feb 28th`. –  Jan 07 '22 at 20:02
1

Try Boost date time library? Easy to use,doesnot have to learn time conversions or anything else,focus on what you want to do.

#include "boost/date_time/gregorian/gregorian.hpp"
#include <iostream>
#include <string>

int
main(int argc, char* argv[])
{

    using namespace boost::gregorian;

    try {
        //Read ISO Standard(CCYYMMDD) and output ISO Extended
        std::string ud("20011009"); //2001-Oct-09
        date d1(from_undelimited_string(ud));
        std::cout << "date is="<<to_iso_extended_string(d1) << std::endl;
        {
            boost::gregorian::months monthObj(6);
            date d2(d1 + monthObj);
            std::cout << "date  6 month later is=" << to_iso_extended_string(d2) << std::endl;
        }
        {
            boost::gregorian::months monthObj(12);
            date d2(d1 + monthObj);
            std::cout << "date  12 month later is=" << to_iso_extended_string(d2) << std::endl;
        }
    }
    catch (std::exception& e) {
        std::cout << "  Exception: " << e.what() << std::endl;
    }


    return 0;
}
kenash0625
  • 657
  • 3
  • 8