C-如何解决添加时间偏移的问题,计算错误

时间:2019-01-18 02:28:10

标签: c time timezone

我尝试向使用时间C函数生成的日期添加时间偏移。 根据偏移值计算错误。如果我增加偏移值,则计算将变为错误!

我在CentOS 5.11上使用gcc

#include <stdio.h>
#include <time.h>
#define MAX_SIZE 80

int main( int argc, char * argv[] ) {

    time_t timestamp, offset;
    struct tm *pTime;
    char buffer[ MAX_SIZE ];

    //timestamp = time( NULL );
    timestamp = 1470356033L;
    printf("timestamp = %ld\n", timestamp);

    // offset calculation
    offset = atol(argv[1]) * (24L * 60L * 60L); 
    printf("offset = %ld\n", offset);

    timestamp += offset;
    printf("timestamp = %ld\n", timestamp);

    pTime = localtime( & timestamp );

    strftime( buffer, MAX_SIZE, "%d/%m/%Y %H:%M:%S", pTime );
    printf( "Date and french time : %s\n", buffer );

    return 0;
}

./testDate 0
timestamp = 1470356033
offset = 0
timestamp = 1470356033
Date and french time : 05/08/2016 02:13:53
This Result is OK, it is reference date without offset 

./testDate 4
timestamp = 1470356033
offset = 345600
timestamp = 1470701633
Date and french time : 09/08/2016 02:13:53
This Result is also OK, it is reference date with 4 days offset 

./testDate 90
timestamp = 1470356033
offset = 7776000
timestamp = 1478132033
Date and french time : 03/11/2016 01:13:53
This Result is wrong, it is reference date with 90 days offset.
Date is OK but 1 hour is missing, it should be 02:13:53 but actual output is 01:13:53

1 个答案:

答案 0 :(得分:3)

time_t类型代表Unix time,即自1970年1月1日星期四00:00:00 UTC以来的秒数,减去leap秒。

(POSIX clock_gettime()界面可能会增加对CLOCK_TAI的支持,除了包括 leap秒外,其他支持都将是相同的。)

对于日期处理,最好使用localtime()gmtime()提供的标准C分解时间struct tm

localtime()使用当前时区。 (Linux系统在/etc/timezone中设置了默认时区,但是每个用户都可以通过设置TZ环境变量来覆盖它。有关如何执行此操作的详细信息,请参见tzset() POSIX.1函数。 )gmtime()使用UTC。

“技巧”是,如果您在描述当前时区中日期和时间的struct tm上调用mktime(),则 first 首先将字段标准化,然后返回Unix时间,作为与该日期和本地时间相对应的time_t。例如,如果一个月中的某天是45,它将调整日,月和年(及相关字段)以反映实际日期。

因此,如果您想从现在起五天零六个小时找出日期和时间:

    time_t     now, then;
    struct tm *t;

    now = time(NULL);
    t = localtime(&now);

    printf("Now is %llu = %04d-%02d-%02d %02d:%02d%02d\n",
           (unsigned long long)now,
           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
           t->tm_hour, t->tm_min, t->tm_sec);

    t->tm_hour += 6;
    t->tm_mday += 5;
    t->tm_isdst = -1; /* Don't know if DST or not; please guess. */
    then = mktime(t);

    printf("Then is %llu = %04d-%02d-%02d %02d:%02d:%02d\n",
           (unsigned long long)then,
           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
           t->tm_hour, t->tm_min, t->tm_sec);

如果我们省略打印nowthen的值,那么上面的代码就是完全标准的C代码,并且可以在所有当前操作系统上使用。

如果您使用Linux或其他POSIXy系统(Mac,BSD),则最好使用

    time_t     now, then;
    struct tm  tbuffer, *t;

    now = time(NULL);
    t = localtime_r(&now, &tbuffer);

    printf("Now is %llu = %04d-%02d-%02d %02d:%02d%02d\n",
           (unsigned long long)now,
           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
           t->tm_hour, t->tm_min, t->tm_sec);

    t->tm_hour += 6;
    t->tm_mday += 5;
    t->tm_isdst = -1; /* Don't know if DST or not; please guess. */
    then = mktime(t);

    printf("Then is %llu = %04d-%02d-%02d %02d:%02d:%02d\n",
           (unsigned long long)then,
           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
           t->tm_hour, t->tm_min, t->tm_sec);

区别在于localtime()返回指向静态分配缓冲区的指针,并且对该缓冲区的另一个调用(即使在另一个线程中)也将覆盖其内容。 POSIX.1 localtime_r()带有第二个参数,即指向struct tm的指针,取而代之的是存储结果。