0

I want to calculate what will be the Epoch Time after 3 months after current date. Following code is giving me current one:

time_t t = time(0);   // get time now
printf("Time=%ld\n", t);

Is there any Linux/Unix api to get this? Note: Will consider leap year and months days variation. Calculation will be according to current system time zone settings and calendar (Linux OS) Thanks.

  • 3 months later in what calendar, and what time zone? If this were "hours" or something similar, it wouldn't matter - but months vary in length. – Jon Skeet Nov 04 '14 at 07:11
  • @Jon Skeet In months it will vary in length that is why the problem occurred and i can't calculate it .... for ur fst 2 qus: in which machine my program runs-it may run in different timezone worldwide (i guess) – iDebD_gh Nov 04 '14 at 07:13
  • http://stackoverflow.com/questions/906034/calculating-future-epoch-time-in-c-sharp Qus asked in C#...but no ans in c –  Nov 04 '14 at 07:15
  • Right, so you want to use the system local time zone... but always in the Gregorian calendar? Or do you want to use the system local calendar as well? What do you want to do if (say) you're adding 3 months to October 30th? Do you want February 28th/29th depending on whether the target is a leap year, or do you want March 1st? You really need to pin down your requirements fully - at which point, I'd expect any decent date/time library to make it easy to achieve. – Jon Skeet Nov 04 '14 at 07:15
  • 2
    This may help: http://en.cppreference.com/w/c/chrono/mktime . The example given actually computes 100 months in the past. Easy to change to +3 for 3 months in the future. – Michael Petch Nov 04 '14 at 07:16
  • @JaiHindRubik's: No, that's not the same question - because it's talking about 10 minutes, not 3 months. That doesn't require extra information about calendars etc. – Jon Skeet Nov 04 '14 at 07:16
  • @JonSkeet I want to consider every thing...Leap year and months variation....need exact calculation. –  Nov 04 '14 at 07:19

1 Answers1

5

In principle, the combination of localtime() and mktime() will allow you to do it:

time_t now = time(0);
struct tm *tp = localtime(&now);
tp->tm_mon += 3;
time_t then = mktime(tp);

The mktime() function will also adjust the members of tp to be appropriate. Experiment with what happens at the ends of the month (e.g. November 30th + 3 months). There's an element of "you get what you get" (or maybe "you get what you deserve"); adding months to a date is an ill-defined operation. If your mktime() does not do what you think you need, then you'll need to consider whether to write your own or search for one that does what you want. You should definitely have a comprehensive suite of test cases with known answers and validate that your mktime() produces the answer you want it to produce.

For example:

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

static void check_time(time_t now, int n_months)
{
    struct tm *tp = localtime(&now);
    char time_buf[64];
    printf("%10lu + %d months\n", (unsigned long)now, n_months);
    strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", tp);
    printf("  %10lu = %s\n", (unsigned long)now, time_buf);
    tp->tm_mon += n_months;
    time_t then = mktime(tp);
    strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", tp);
    printf("  %10lu = %s\n", (unsigned long)then, time_buf);
}

int main(void)
{
    time_t times[] =
    {
        1322504430, // 2011-11-28 10:20:30 -08:00
        1322590830, // 2011-11-29 10:20:30 -08:00
        1322677230, // 2011-11-30 10:20:30 -08:00
        1417198830, // 2014-11-28 10:20:30 -08:00
        1417285230, // 2014-11-29 10:20:30 -08:00
        1417371630, // 2014-11-30 10:20:30 -08:00
        1391192430, // 2014-01-31 10:20:30 -08:00
    };

    enum { NUM_TIMES = sizeof(times) / sizeof(times[0]) };

    for (int i = 0; i < NUM_TIMES; i++)
        check_time(times[i], 3);

    return 0;
}

Example output from Mac OS X 10.10:

1322504430 + 3 months
  1322504430 = 2011-11-28 10:20:30
  1330453230 = 2012-02-28 10:20:30
1322590830 + 3 months
  1322590830 = 2011-11-29 10:20:30
  1330539630 = 2012-02-29 10:20:30
1322677230 + 3 months
  1322677230 = 2011-11-30 10:20:30
  1330626030 = 2012-03-01 10:20:30
1417198830 + 3 months
  1417198830 = 2014-11-28 10:20:30
  1425147630 = 2015-02-28 10:20:30
1417285230 + 3 months
  1417285230 = 2014-11-29 10:20:30
  1425234030 = 2015-03-01 10:20:30
1417371630 + 3 months
  1417371630 = 2014-11-30 10:20:30
  1425320430 = 2015-03-02 10:20:30
1391192430 + 3 months
  1391192430 = 2014-01-31 10:20:30
  1398968430 = 2014-05-01 11:20:30

If you don't like 3 months after 31st January being 1st May (as well as 3 months after 1st February), then the Mac OS X 10.10 version of mktime() is not the one for you.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • I would like to hope there's a date/time library which makes it more pleasant than this - in particular, I've no idea what `mktime` will do with a month number of 13. (It *may* do the right thing, but the man page doesn't appear to say how the value is normalized.) Additionally, by using the system default time zone there's always the possibility that the resulting local time will be ambiguous or skipped... – Jon Skeet Nov 04 '14 at 07:25
  • @JonSkeet: With a month of 13, it will normalize to (January) February of the next year. Trickier is what happens with 30th February, or 31st of February, April, June, September, November, or 29th February in a non-leap year. – Jonathan Leffler Nov 04 '14 at 07:27
  • Wouldn't it normalize to February of the next year, given that months are 0-based? – Jon Skeet Nov 04 '14 at 07:27
  • Yes; it would be February...it normalizes values in the primary date/time members — it ignores the input values in `tm_wday` and `tm_yday`, but sets them when it is done. – Jonathan Leffler Nov 04 '14 at 07:29
  • @JonathanLeffler Applauding answer, Yes, I want 3 months after 31st January being 1st May . I also got same output in my Linux(3.11)...thanks –  Nov 04 '14 at 08:25
  • Note that 3 months after 2014-11-30 is a day later than 3 months after 2014-12-01. This isn't immediately intuitive. (Add `1417458030` and `1417544430` to the test cases in my answer to see this behaviour.) – Jonathan Leffler Nov 04 '14 at 15:50