用C语言计算时间差

用C语言计算时间差,c,time,standard-library,C,Time,Standard Library,我试着使用库,但它似乎不支持追溯到1900年之前,甚至可能超过某个x年的时间 我的问题是: 我是否可以使用计算以下时间之间的时差(以秒、小时或天为单位),例如: 2014年5月1日和566年1月24日 是否支持闰年?也就是说,如果我计算上面的差值,那算闰年吗?很明显,我可以做如下的事情: int toDays(struct tm *date) { int days = date->tm_yday; int year; for (year = 1; year <

我试着使用
库,但它似乎不支持追溯到1900年之前,甚至可能超过某个x年的时间

我的问题是:

  • 我是否可以使用
    计算以下时间之间的时差(以秒、小时或天为单位),例如:

    2014年5月1日和566年1月24日

  • 是否支持闰年?也就是说,如果我计算上面的差值,那算闰年吗?很明显,我可以做如下的事情:

    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;
    }
    
    int今天(struct tm*日期)
    {
    整数天=日期->tm_yday;
    国际年;
    对于(年=1;年<日期->tm_年;++年)
    {
    天数+=年?366:365;
    }
    返程天数;
    }
    
  • 但是再一次-
    tm_年
    从1900年算起,对吗

    老实说,我不了解这个结构,我可能会自己写一个,除非有人能帮我。当我想像问题1那样计算年份时,使用
    有什么意义吗?

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

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

    struct tm start_date, end_date;
    
    然后根据日期用数据填充结构

    然后使用
    difftime()
    as

    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);
    }
    
    #包括
    #包括
    int main()
    {
    现在是时候了;
    struct tm开始日期、结束日期;
    开始日期=*本地时间(&now);
    结束日期=*本地时间(&now);
    开始日期tm年=1013;
    end_date.tm_year=1015;
    无符号long int diff=difftime(mktime(&end_日期),mktime(&start_日期));
    printf(“DIFF:[%lu]”,DIFF);
    返回(0);
    }
    
    如果您有一个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;
    }
    
    回顾过去,事情并不是那么好。将两个年值除以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年是英国及其殖民地的转换日期)。人们通常将“前公历”向后应用

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

  • 现在使用的主要日历:公历1582年开始。它在世界各地的采用情况各不相同。所以像566y年1月24日这样的日期需要限定

  • 让我们假设OP的
    时间
    在2000到2400之间工作,并且所有日期都是根据需要向后和向前的:

    使用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;
    }
    
    long long day\u编号(整数年、整数月、整数日){
    #定义DaysPer400Year(400LL*365+97)
    long long yearll=年份-2000LL;
    年份=yearll%400;
    int century400=全年/400;
    如果(年份<0){
    年份+=400;
    百分之四百--;
    }
    长数=百分之400*天或400年;
    编号+=操作日编号(年+2000,月,日);
    返回号码;
    }
    
    这取决于您的O/S和库,以及您机器的“比特数”。32位系统可能存在1902到2037范围以外的问题(以1970-01-01 00:00:00+00:00为历元的32位有符号整数)。64位系统通常有一个64位的
    时间类型,其日期范围非常大(宇宙死亡类型刻度)。是的,函数知道闰年。他们是否理解世界上哪个地区从儒略历改为公历(如果真的是这样的话)的所有变幻莫测之处,这是一个单独的讨论。时区也很复杂!@OleksandrKravchuk的可能副本:为什么这是一个副本?这大约是整秒,不是毫秒或纳秒,不是吗?在
    2744y
    566y
    y
    的意义是什么?你的意思是这些年是在28和6千年?或者年份是2744 CE和566 CE(CE也被称为AD;它是公历)?或者别的什么?如果你要回到566年1月24日这样的日期,你应该知道早期日期不使用公历。使用
    struct tm tm1={.tm_year=y1-1900,.tm_mon=m1-1,.tm_mday=d1}。。。时间t1=mktime(&tm1)
    ,这是否会将其他字段初始化为0?@chux:yes-缺少初始值设定项等同于默认(实际上为零)初始值设定项。
    difftime(t1,t2)/(24*60*60L)
    避免了“不可靠的赋值”。
    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;
    }