计算C中的时差

时间:2015-11-02 07:40:19

标签: c time standard-library

我尝试使用<time.h>库,但似乎<time.h>并不真正支持早于1900年的时间,可能超过x年。

我的问题是:

  1. 我可以使用<time.h>计算时间差(以秒,小时或天为单位),例如:

    5月1日2744y和1月24日566y

  2. <time.h>是否支持闰年?这意味着如果我计算出上面的差异 - 这会计算闰年吗?我显然可以做出类似的事情:

    int toDays(struct tm *date)
    {
        int days = date->tm_yday;
        int year;
        for (year = 1; year < date->tm_year; ++year)
        {
            days += isLeapYear(year) ? 366 : 365;
        }
        return days;
    }
    
  3. 但是再次 - tm_year从1900算起,我是对的吗?

    老实说,我对这种结构并不了解,我可能会自己写一个,除非有人可以帮我这个。当我想计算问题1中的年份时,使用<time.h>是否有意义?

3 个答案:

答案 0 :(得分:1)

您可以尝试使用difftime()函数。

首先,您必须定义两个可以保存所需数据的结构,例如

struct tm start_date, end_date;

然后根据您的日期填充结构中的数据。

然后使用difftime()作为

seconds = difftime(mktime(&end_date),mktime(&start_date))

以下示例将帮助您了解流程。

#include<stdio.h>
#include<time.h>
int main()
{
   time_t now;
   struct tm start_date, end_date;
   start_date = *localtime(&now);
   end_date = *localtime(&now);

   start_date.tm_year = 1013;
   end_date.tm_year = 1015;

   unsigned long int diff = difftime(mktime(&end_date), mktime(&start_date));
   printf("DIFF: [%lu]",diff);
   return(0);
}

答案 1 :(得分:1)

如果你有一个64位系统,如Mac OS X(使用10.11 El Capitan),那么这可行:

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

int main(void)
{
    int y1 = 27440;
    int m1 = 5;
    int d1 = 1;
    int y2 = 5660;
    int m2 = 1;
    int d2 = 24;
    struct tm tm1 = { .tm_year = y1 - 1900, .tm_mon = m1 - 1, .tm_mday = d1 };
    struct tm tm2 = { .tm_year = y2 - 1900, .tm_mon = m2 - 1, .tm_mday = d2 };
    time_t t1 = mktime(&tm1);
    time_t t2 = mktime(&tm2);
    size_t dt = t1 - t2;       // Dodgy assignment…I get away with it, but…

    char buffer[128];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm1);
    printf("t1 = %20s\n", buffer);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm2);
    printf("t2 = %20s\n", buffer);

    printf("t1 = %" PRIdMAX "\n", (intmax_t)t1);
    printf("t2 = %" PRIdMAX "\n", (intmax_t)t2);
    printf("dt = %zu seconds\n", dt);
    printf("dt = %zu hours\n", dt / 3600);
    printf("dt = %zu days\n", dt / (24 * 3600));
    return 0;
}

我得到的输出是:

t1 = 27440-05-01 00:00:00
t2 =  5660-01-24 00:00:00
t1 = 803766009600
t2 = 116447184000
dt = 687318825600 seconds
dt = 190921896 hours
dt = 7955079 days

尝试追溯的事情并不是那么好。将两个年份值除以10得出:

t1 =  2744-05-01 00:00:00
t2 =  0566-01-24 00:00:00
t1 = 24435504000
t2 = -1
dt = 24435504001 seconds
dt = 6787640 hours
dt = 282818 days

请注意-1表示错误;系统不愿意在第一个千年中使用日期(这导致dt计算不准确)。 AFAICT,在Mac上,mktime()不会比32位有符号值的时间更早回来 - 它接受1902-01-01但拒绝1901-01-01。 32位限制是:

-2147483647 = Fri Dec 13 12:45:53 1901  (US/Pacific)

测试代码:

static int test_year(int year)
{
    struct tm tm1 = { .tm_year = year - 1900, .tm_mon = 0, .tm_mday = 1 };
    time_t t1 = mktime(&tm1);
    return (t1 != -1);
}

static void early_year(void)
{
    int y_lo =  566;
    int y_hi = 1902;
    assert(test_year(y_lo) == 0);
    assert(test_year(y_hi) == 1);

    while (y_lo != y_hi)
    {
        int y_md = (y_lo + y_hi) / 2;
        printf("lo = %4d; hi = %4d; md = %4d\n", y_lo, y_hi, y_md);
        if (test_year(y_md) == 0)
            y_lo = y_md + 1;
        else
            y_hi = y_md - 1;
    }
    printf("Valid back to %4d\n", y_lo);
}

调用该代码的结果:

lo =  566; hi = 1902; md = 1234
lo = 1235; hi = 1902; md = 1568
lo = 1569; hi = 1902; md = 1735
lo = 1736; hi = 1902; md = 1819
lo = 1820; hi = 1902; md = 1861
lo = 1862; hi = 1902; md = 1882
lo = 1883; hi = 1902; md = 1892
lo = 1893; hi = 1902; md = 1897
lo = 1898; hi = 1902; md = 1900
lo = 1901; hi = 1902; md = 1901
Valid back to 1902
正如俗言所说,YMMV;这取决于你正在进行的系统。请注意,随着时间的推移,时钟和日历变得越来越不可靠。无视1712年2月30日(在瑞典)的这种细节,你可以在1584年和20世纪之间获得各种各样的日期,这些日期是国家从儒略历切换到格里高利历(1752年是英国和她的殖民地的转换日期,例如)。人们通常向后应用“预感格里高利历”日历。

答案 2 :(得分:0)

  1. 数据范围time.h功能因系统而异。假设他们在1970-2037工作是合理的。许多系统的工作范围更广。 OP似乎早在1900年就可以使用。

  2. 今天使用的主要日历:格里高利开始于1582年。它在全世界的采用各不相同。所以像1月24日566y那样的日期需要资格。

  3. 让我们假设OP的time工作时间超过2000到2400,并且所有日期都是Gregorian, projected根据需要向后和向前转移:

    使用400格里高年400*365+97天的“技巧”(这是7的倍数)。

    所以要使用OP的功能获得#天数,这有望在2000-2400的400年范围内工作:

    long long day_number(int year, int, month, int day) {
      #define DaysPer400Year (400LL*365 + 97)
      long long yearll = year - 2000LL;
      year = yearll % 400;
      int century400 =  yearll/400;
      if (year < 0) {
        year += 400;
        century400--;
      }
      long long number = century400 * DaysPer400Year;
      number += OP_day_number(year + 2000, month, day);
      return number;
    }