Calculating number of days since a particular date not working as expected

116 Views Asked by At

I wrote a function in C to calculate how many days it has been since January 1, 2000. However, it doesn't work correctly for some years (e.g. it works for May 5, 2020, but not for May 5, 2029). For some years it determines the number of days correctly, for others 1 day less, and for some two or three days less. Which part of the code could cause this problem?

bool isLeapYear(int y) {
    if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) 
        return true; 
    else 
        return false; 
}

int days_since(int y, int m, int d)
{   int m_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int leap_count = 0;
    int years_index = y-2000;
    for (int i=2001; i<=y; i++){
        if(isLeapYear(i))
            leap_count ++;
    }
    int add_years = 366 * (leap_count) + 365 * (years_index-leap_count);

    int add_months = 0;
    if (isLeapYear(y))
        m_days[1] = 29;
    
    for (int i=0; i<m-1; i++)
        add_months += m_days[i];
    
    int add_days = d-1;

    int total_days = add_years + add_months + add_days;

    return total_days;
}
1

There are 1 best solutions below

4
On

Dealing with February 29th in the middle of the year is a pain and OP's code has troubles with that too.

I do not see a simple fix of OP's code.

Instead, move leap day to the end of the year by making March the first month and January/February the last months of the previous year. That's what the Romans did and then the 8th month is October and the 10th month is December. This simplifies much code by putting leap day concerns at the year's end.
Notice days_since_March1[] below is the same for leap years and non-leap years and the leap year calculation is simple.

#include <assert.h>

#define JANUARY 1
#define MARCH 3
#define DECEMBER 12
#define MONTHS_PER_YEAR 12
#define GREGORIAN_FIRST_FULL_YEAR 1583
#define EPOCH_2000Jan1 730426

int days_since2000Jan1(int y, int m, int d) {
  assert(y >= GREGORIAN_FIRST_FULL_YEAR);
  assert(m >= JANUARY && m <= DECEMBER);
  if (m < MARCH) {
    m += MONTHS_PER_YEAR;
    y--;
  }
  int months_since_March = m - MARCH;
  static const short days_since_March1[12] = {0, 31, 61, 92, 122, 153, 184, 214,
      245, 275, 306, 337};
  return y * 365 + y / 4 - y / 100 + y / 400
      + days_since_March1[months_since_March] + d - EPOCH_2000Jan1;
}