3

I want to find the number of days between two months. I use Xcode but don't want to go through the trouble of installing boost or 'date.h', so I tried to do it more primitively but somehow the code keeps breaking at a certain point:

    for ( it=mymap.begin() ; it != mymap.end(); it++ ) {
        auto nx = next(it);

        if (it->second.patientID == nx->second.patientID) {

            //31 28 31 30 31 30 31 31 30 31 30 31
            yue = it->second.month;
            yue2 = nx->second.month;
            sincejan1 = 0;
            sincejan = 0;

            //it keeps breaking at the line below
            if (abs(yue-yue2) > 0) {

            if (yue ==12)
                sincejan1 = 365-31;
            if (yue ==11)
                sincejan1 = 365-31-30;
            if (yue ==10)
                sincejan1 = 365-31-30-31;
            if (yue ==9)
                sincejan1 = 365-31-30-31-30;
            if (yue ==8)
                sincejan1 = 31+28+31+30+31+30+31+31;
            if (yue ==7)
                sincejan1 = 31+28+31+30+31+30+31;
            if (yue ==6)
                sincejan1 = 31+28+31+30+31+30;
            if (yue ==5)
                sincejan1 = 31+28+31+30+31;
            if (yue ==4)
                sincejan1 = 31+28+31+30;
            if (yue ==3)
                sincejan1 = 31+28+31;
            if (yue ==2)
                sincejan1 = 31+28;
            if (yue ==1)
                sincejan1 = 31;

            if (yue2 ==12)
                sincejan = 365-31;
            if (yue2 ==11)
                sincejan = 365-31-30;
            if (yue2 ==10)
                sincejan = 365-31-30-31;
            if (yue2 ==9)
                sincejan = 365-31-30-31-30;
            if (yue2 ==8)
                sincejan = 31+28+31+30+31+30+31+31;
            if (yue2 ==7)
                sincejan = 31+28+31+30+31+30+31;
            if (yue2 ==6)
                sincejan = 31+28+31+30+31+30;
            if (yue2 ==5)
                sincejan = 31+28+31+30+31;
            if (yue2 ==4)
                sincejan = 31+28+31+30;
            if (yue2 ==3)
                sincejan = 31+28+31;
            if (yue2 ==2)
                sincejan = 31+28;
            if (yue2 ==1)
                sincejan = 31;
            }

            monthDiff = sincejan1 - sincejan;
        }
    }

I'm not sure what's wrong or if this is an okay way to do this. I would appreciate greatly any help/advice! I'm a programming beginner.

aspn
  • 37
  • 8
  • 3
    *so I tried to do it more primitively* -- You can't do "primitive" date processing. That's why libraries exist. It isn't as easy as you seem to believe it is. – PaulMcKenzie Oct 24 '15 at 23:39
  • 2
    What if February has 29 day? which years is that the case? if your only taking dates in this millennium you don't have to take case of missing days when the calender changed, Gregorian, Julian, pre-Julian(?) – Surt Oct 24 '15 at 23:42
  • 1
    To the OP: You have to dig down and go into weeds if you want to process dates correctly -- it could be a full time job. If you're not ready for this, use a library. – PaulMcKenzie Oct 24 '15 at 23:45
  • Hi there, thanks for the tips. My data only work with 2014-15 dates so I wanted a simple fix, but I guess I didn't think it through enough. I'm a programming beginner and couldn't find a step-by-step instructions on how to use terminal on my mac to install a library - can anyone point me in the right direction? I'm scared of doing something wrong in there and messing things up... – aspn Oct 25 '15 at 00:32
  • 1
    Hi, aspn- you're correct: there *are* (relatively...) "simple fixes". You absolutely don't need to "install a library" for this problem. If you choose to, however, the instructions will probably vary from library to library. – paulsm4 Oct 25 '15 at 02:54

2 Answers2

1

I would recommend using "difftime":

http://www.manpagez.com/man/3/difftime/

ADDENDUM:

I thought I'd try out some sample code on Eclipse/CDT ... but my CDT install wasn't working :( I wound up re-installing.

ANYWAY:

datediff.c:

#include <stdio.h>   /* printf() etc */
#include <time.h>    /* time(), difftime(), time_t, struct tm */
#include <stdlib.h>  /* atoi() */

#define SECONDS_IN_DAY (60 * 60 * 24) /* Note importance of parentheses */

int
datediff(int m1, int m2) {
        double diff_seconds;
        int diff_days;

        /* Populate timeptr structs */
        time_t now = time(NULL);
        struct tm *tm_ptr = gmtime(&now);
        struct tm t1 = *tm_ptr, t2 = *tm_ptr;
        t1.tm_mon = m1;
        t2.tm_mon = m2;

    /* Compute difference between m1 and m2 */
        diff_seconds = difftime(mktime(&t1), mktime(&t2));
        diff_days = diff_seconds / SECONDS_IN_DAY;
        if (diff_days < 0) diff_days = -diff_days;
        return diff_days;
}

int
main (int argc,char *argv[]) {
        /* Input: month1, month2 */
        if (argc != 3) {
                printf ("USAGE: datediff m1 m2\n");
                return 1;
        }

        /* Compare dates */
        printf ("#/months= %d\n", datediff(atoi(argv[1]), atoi(argv[2])));

        /* Exit */
        return 0;
}

Sample output:

./datediff 9 1
#/months= 242

./datediff 1 9
#/months= 242

./datediff 9 8

./datediff 9 8
#/months= 30

./datediff 3 2
#/months= 31
paulsm4
  • 114,292
  • 17
  • 138
  • 190
1

This is similar to an interview question I ask prospective hires to code for me. (And for purposes of interview evaluation, they are not allowed to use the built in date/time functions).

And the OP's problem is simplified to measuring the delta in days of dates within the same year - so that makes things easier.

To start, we need a simple function to tell us if the year we are dealing with is a leap year, because at some point in the code, we'll have to deal with leap years. And, leap year is a bit more than just "every four year". But you already know that.

bool isLeapYear(int year)
{
    bool isDivisibleByFour = !(year % 4);
    bool isDivisibleBy100 = !(year % 100);
    bool isDivisibleBy400 = !(year % 400);
    return (isDivisibleBy400) || (isDivisibleByFour && !isDivisibleBy100);
}

And we'll need another helper function to return the number of days in a month and it needs to account for for leap years in February.

int getDaysInMonth(int month, int year)
{
    int days_in_month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };

    int result = days_in_month[month-1];
    if ((month == 2) && isLeapYear(year))
    {
        result++;
    }
    return result;
}

Assume in the above code that "January" would be represented by "month == 1" and December is "month == 12". Hence, the [month-1] thing in the array lookup. We would add some parameter validation to the above code, but it should work for purposes of discussion.

Now we have a way to count days in a month, we need to a function that will tell us "how many days since the beginning of the year" for a given month/day/year.

int getDayOfYear(int month, int day, int year)
{
    int count = 0;
    int m = 1;

    while (m != month)
    {
        count += getDaysInMonth(m, year);
        m++;
    }
    count += day - 1;
    return count;
}

The function above will return "0" for (1,1,2015) and "364" for (12,31,2015). Again, parameter validation would be needed for production code.

Now to compute the difference in days between any two days of the same year:

int getDiffOfDaysInSameYear(int month1, int day1, int month2, int day2, int year)
{
    int day_of_year1 = getDayOfYear(month1, day1, year);
    int day_of_year2 = getDayOfYear(month2, day2, year);
    return day_of_year2 - day_of_year1;
}

Let's test it out:

int main()
{
    int x = getDiffOfDaysInSameYear(4,4, 10,24, 2015); // number of days to get to  10/24/2015 from 4/4/2015
    printf("The delta in days between April 4 and October 2015 is: %d days\n", x);
    return 0;
}

Prints out: The delta in days between April 4 and October 2015 is: 203 days

If you want to simplify it to just counting days between months, then just pass in "1" for the days.

int main()
{
    int x = getDiffOfDaysInSameYear(5, 1, 11, 1, 2015);
    printf("The delta in days between May and November is %d\n", x);
    return 0;
}

Prints out: The delta in days between May and November is 184

Hope this helps.

selbie
  • 100,020
  • 15
  • 103
  • 173
  • Very clear. It does however do more work than needed to calculate the difference between dates, such as when both dates are near the end of the year. Optimize? ;) – Daniel Stevens Oct 25 '15 at 05:07
  • @DanielStevens - Certainly *could* be optimized at the expense of being less clear and less maintainable. Another solution could be to hardcode in a 2d-array (matrix) of `int day_of_year[12][31]` and `int days_of_leap_year[12][31]` and use that to for `getDayOfYear` routine instead of looping. It *might be faster*, because math loops are often actually faster than array lookups. The only way to know is to do some benchmarking with a profiling tool. Optimize when the business depends on it. – selbie Oct 25 '15 at 05:23
  • Hi selbie, thanks for the clear example! It was very informative, especially for a beginner like me. It certainly added much more sophistication to what I had. – aspn Oct 25 '15 at 07:06
  • I think you could optimize for this specific use case without really losing much readability or maintainability. Your function `getDayOfYear` basically has an implied difference date of January 1st. You could parametrize those constants (month = 1, day = 1). – Daniel Stevens Oct 25 '15 at 15:20