计算自特定日期未按预期工作以来的天数

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

提问人:Nare Avetisyan 提问时间:11/8/2023 最后编辑:Nare Avetisyan 更新时间:11/10/2023 访问量:100

问:

我用 C 语言编写了一个函数来计算自 2000 年 1 月 1 日以来已经过去了多少天。但是,它在某些年份无法正常工作(例如,它适用于 2020 年 5 月 5 日,但不适用于 2029 年 5 月 5 日)。对于某些年份,它正确地确定了天数,对于其他年份,它减少了一天,对于某些年份,它减少了两到三天。代码的哪一部分可能导致此问题?

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;
}
c 闰年

评论

0赞 Weather Vane 11/8/2023
请显示功能。isLeapYear()
2赞 stark 11/8/2023
无论年份如何,1 月和 2 月的大部分时间都没有闰日。
0赞 Nare Avetisyan 11/8/2023
@WeatherVane编辑了问题以显示 isLeapYear()。
0赞 Jose Manuel Gomez Alvarez 11/8/2023
你为什么不直接转换为Unix时间,然后从秒数(Unix纪元的差异)计算天数
1赞 Weather Vane 11/8/2023
谢谢。循环似乎不正确。应该是 ?您没有计算 2000 年(闰年),并且您已经计算了两次当前年份(因为您在数组中用 29 覆盖了 28)。for (int i=2001; i<=y; i++)for (int i=2000; i<y; i++)

答:

2赞 chux - Reinstate Monica 11/9/2023 #1

在年中处理 2 月 29 日是一件痛苦的事情,OP 的代码在这方面也有问题。

我没有看到 OP 代码的简单修复。

相反,将闰日移到年底,将 3 月定为第一个月,将 1 月/2 月定为上一年的最后一个月。这就是罗马人所做的,然后第 8 个月是 10 月 ober,第 10 个月是 12 月余烬。通过在年底放置闰日关注点,这简化了许多代码。
请注意,闰年和非闰年是相同的,闰年的计算很简单。
days_since_March1[]

#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;
}

评论

0赞 chux - Reinstate Monica 11/9/2023
对于那些喜欢限制较少的月份和公式与表格的人:int days_since2000Jan1(int y, int m, int d) { assert(y >= GEGORIAN_FIRST_FULL_YEAR); y += m / MONTHS_PER_YEAR; m %= MONTHS_PER_YEAR; while (m < MARCH) { m += MONTHS_PER_YEAR; y--; } int days_since_March1 = (979 * m - 2919) >> 5; // About 30.6 days/month return y * DAYS_PER_COMMON_YEAR + y / 4 - y / 100 + y / 400 + days_since_March1 + d - EPOCH_2000Jan1; }
1赞 Fe2O3 11/9/2023
有没有办法用这些填充数组,然后将好日子和坏日子分开?:-)
1赞 chux - Reinstate Monica 11/9/2023
@Fe2O3,好日子
0赞 Fe2O3 11/9/2023
我遇到过一些蛋白石矿工,他们不同意那篇文章的前提,或者至少是标题......:-)