Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Arithmetics on calendar dates in C or C++ (add N days to given date)

I have been given a date, Which I am taking as an input like (day, month, year): 12, 03, 87.

Now I need to find out the date after n days.

I have written code for this, But its not efficient. Can you please tell me any good logic which works faster and have less complexity.

#include <stdio.h>

static int days_in_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day, month, year;

unsigned short day_counter;

int is_leap(int y) {
    return ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0);
}

next_day()
{
    day += 1; day_counter++;
    if (day > days_in_month[month]) {
        day = 1;
        month += 1;
        if (month > 12) {
            month = 1;
            year += 1;
            if (is_leap(year)) {
                days_in_month[2] = 29;
            } else {
                days_in_month[2] = 28;
            }
        }
    }
}

set_date(int d, int m, int y) 
{
    m < 1 ? m = 1 : 0;
    m > 12 ? m = 12 : 0;
    d < 1 ? d = 1 : 0;
    d > days_in_month[m] ? d = days_in_month[m] : 0;
    if (is_leap(y)){
        days_in_month[2] = 29;
    } 
    else {
        days_in_month[2] = 28;
    }
    day = d;
    month = m;
    year = y;
}

skip_days(int x)
{
    int i;
    for (i=0;i<x;i++) next_day();
}

print_date()
{
    printf ("day: %d month: %d year: %d\n", day, month, year);
}

int main(int argc, char **argv)
{
    int i;

    set_date(5, 2, 1980);
    skip_days(40);
    day_counter = 0;
    /* after this call next_day each day */

    print_date();
    return 0;
}
like image 794
vivek jain Avatar asked Mar 27 '13 20:03

vivek jain


2 Answers

Can you please tell me any good logic which works faster and have less complexity.

If this exact thing is indeed a performance critical part of your application, you're likely doing something wrong. For the sake of clarity and correctness, you should stick to the existing solutions. Select the one that is most appropriate to your development environment.


The C approach:

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

int main()
{        
    /* initialize */
    int y=1980, m=2, d=5;    
    struct tm t = { .tm_year=y-1900, .tm_mon=m-1, .tm_mday=d };
    /* modify */
    t.tm_mday += 40;
    mktime(&t);
    /* show result */
    printf("%s", asctime(&t)); /* prints: Sun Mar 16 00:00:00 1980 */
    return 0;
}

The C++ without using Boost approach:

#include <ctime>
#include <iostream>

int main()
{        
    // initialize
    int y=1980, m=2, d=5;
    std::tm t = {};
    t.tm_year = y-1900;
    t.tm_mon  = m-1;
    t.tm_mday = d;
    // modify
    t.tm_mday += 40;
    std::mktime(&t);
    // show result
    std::cout << std::asctime(&t); // prints: Sun Mar 16 00:00:00 1980
}

The Boost.Date_Time approach:

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

int main()
{
    using namespace boost::gregorian;
    // initialize
    date d(1980,2,5);
    // modify
    d += days(40);
    // show result
    std::cout << d << '\n'; // prints: 1980-Mar-16
}
like image 106
moooeeeep Avatar answered Oct 23 '22 03:10

moooeeeep


The standard library mktime function includes a trick to make it easy to add a number of months or days into a given date: you can give it a date such as "45th of February" or "2nd day of the 40th month" and mktime will normalize it into a proper date. Example:

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

int main() {
    int y = 1980;
    int m = 2;
    int d = 5;
    int skip = 40;

    // Represent the date as struct tm.                                                           
    // The subtractions are necessary for historical reasons.
    struct tm  t = { 0 };
    t.tm_mday = d;
    t.tm_mon = m-1;
    t.tm_year = y-1900;

    // Add 'skip' days to the date.                                                               
    t.tm_mday += skip;
    mktime(&t);

    // Print the date in ISO-8601 format.                                                         
    char buffer[30];
    strftime(buffer, 30, "%Y-%m-%d", &t);
    puts(buffer);
}

Compared to doing the arithmetic in seconds using time_t, this approach has the advantage that daylight savings transitions do not cause any problems.

like image 29
han Avatar answered Oct 23 '22 04:10

han