C - Как исправить добавление временного смещения, неправильный расчет - PullRequest
0 голосов
/ 18 января 2019

Я пытаюсь добавить смещение времени к дате, сгенерированной функцией времени C. Расчет неверен в зависимости от значения смещения. если я увеличу значение смещения, расчет станет ложным!

Я использую gcc на CentOS 5.11

#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 голосов
/ 18 января 2019

time_t тип представляет Unix time , количество секунд с четверга, 1 января 1970 года, 00:00:00 UTC, минус високосные секунды.

(Интерфейс POSIX clock_gettime() может увеличить поддержку CLOCK_TAI, которая будет такой же, за исключением , включая високосных секунд.)

Для манипулирования датой лучше использовать стандартное время разбивки C struct tm, как указано в localtime() или gmtime().

localtime() использует текущий часовой пояс. (В системах Linux по умолчанию установлен часовой пояс в /etc/timezone, но каждый пользователь может переопределить его, установив переменную среды TZ. Подробнее о том, как это сделать, см. В функции tzset() POSIX.1. ) gmtime() использует UTC.

«Хитрость» заключается в том, что если вы вызываете mktime() на struct tm, описывающем дату и время в текущем часовом поясе, он сначала нормализует поля, а затем возвращает время 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);

Если мы опускаем печать значений now и then, приведенный выше код является совершенно стандартным кодом 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, где вместо этого сохраняется результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...