Как я могу сравнить 2 даты, конвертируемые из разбитого времени в календарное время? - PullRequest
1 голос
/ 27 апреля 2020

Я спрашиваю, что именно, что говорит название. Очевидно, что-то идет не так в моем следующем коде:

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

int main(void){
    struct tm t1 , t2;

    t1.tm_sec = 0;
    t1.tm_min = 0;
    t1.tm_hour = 0;
    t1.tm_isdst = -1;
    t2 = t1;

    printf("Enter 2 dates:\n");
    scanf("%d/%d/%d %d/%d/%d" , &t1.tm_mday , &t1.tm_mon , &t1.tm_year ,//   Sorry for 
                                &t2.tm_mday , &t2.tm_mon , &t2.tm_year);// lazy coding here
    time_t tm1 , tm2;
    tm1 = mktime(&t1);
    tm2 = mktime(&t2);


    printf("%d" , (int) difftime(tm1 , tm2));
}

Выход всегда равен нулю. Вывод, когда я пытаюсь запустить его так:

C:\Users\...>program
Enter 2 dates:
3/2/2016 12/2/2017
0

1 Ответ

2 голосов
/ 27 апреля 2020

Я подозреваю, что ваши проблемы являются следствием двух факторов:

  1. Вы не вычитаете 1900 из значений года, введенных пользователем, и не вычитаете 1 из номера месяца - см. C11 §7.27.1 компоненты времени для получения информации о немного странном кодировании для tm_year и tm_mon элементов struct tm.
  2. Ваша система использует 32-битную time_t, а не 64-битный time_t.

Вот вариант вашего кода, работающий в 64-битной системе (MacBook Pro, работающий на MacOS Mojave 10.14.6, использующий G CC 9.3.0).

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

static void dump_time(const char *tag, time_t t);
static void dump_struct_tm(const char *tag, const struct tm *tm);

int main(void)
{
    struct tm t1 = { 0 };  /* Probably not essential, but a good idea */

    printf("sizeof(time_t) = %d\n", (int)sizeof(time_t));

    t1.tm_sec = 0;
    t1.tm_min = 0;
    t1.tm_hour = 0;
    t1.tm_isdst = -1;
    struct tm t2 = t1;

    printf("Enter 2 dates:\n");
    int n = scanf("%d/%d/%d %d/%d/%d", &t1.tm_mday, &t1.tm_mon, &t1.tm_year,
                  &t2.tm_mday, &t2.tm_mon, &t2.tm_year);
    if (n != 6)
    {
        fprintf(stderr, "failed to read two dates (n = %d)\n", n);
        return 1;
    }
    struct tm t3 = t1;
    struct tm t4 = t2;

    time_t tm1, tm2;
    tm1 = mktime(&t1);
    tm2 = mktime(&t2);

    dump_struct_tm("t1", &t1);
    dump_struct_tm("t2", &t2);
    dump_time("time-1", tm1);
    dump_time("time-2", tm2);
    printf("%d\n", (int) difftime(tm1, tm2));

    t3.tm_year -= 1900;
    t3.tm_mon  -= 1;
    t4.tm_year -= 1900;
    t4.tm_mon  -= 1;
    time_t tm3 = mktime(&t3);
    time_t tm4 = mktime(&t4);

    dump_struct_tm("t3", &t3);
    dump_struct_tm("t4", &t4);
    dump_time("time-3", tm3);
    dump_time("time-4", tm4);
    printf("%d\n", (int) difftime(tm3, tm4));

    return 0;
}

static void dump_time(const char *tag, time_t t)
{
    char buffer[32];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", localtime(&t));
    printf("%s = %lld (%s)\n", tag, (long long)t, buffer);
}

static void dump_struct_tm(const char *tag, const struct tm *tm)
{
    printf("%s: year = %5d, month = %2d, day = %2d, "
           "hour = %2d, minute = %2d, second = %2d, DST = %d\n",
           tag, tm->tm_year, tm->tm_mon, tm->tm_mday,
           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_isdst);
}

Две функции дампа иллюстрируют удобную технику, которую я использую при отладке - функцию, которая выводит структуру вместе с тегом, который определяет, какой код выводит на этот раз.

При запуске (как date37, составлено из date37.c), я получаю:

$ date37
sizeof(time_t) = 8
Enter 2 dates:
3/2/2016 12/2/2017
t1: year =  2016, month =  2, day =  3, hour =  0, minute =  0, second =  0, DST = 0
t2: year =  2017, month =  2, day = 12, hour =  0, minute =  0, second =  0, DST = 1
time-1 = 61415132400 (3916-03-03 00:00:00)
time-2 = 61447442400 (3917-03-12 00:00:00)
-32310000
t3: year =   116, month =  1, day =  3, hour =  0, minute =  0, second =  0, DST = 0
t4: year =   117, month =  1, day = 12, hour =  0, minute =  0, second =  0, DST = 0
time-3 = 1454482800 (2016-02-03 00:00:00)
time-4 = 1486882800 (2017-02-12 00:00:00)
-32400000
$

Разница между двумя значениями, полученными в результате difftime(), составляет 90000 секунд, количество секунд в дне (86400) плюс количество секунд через час (3600). Компонент «1 день» объясняется тем, что 2016 год был високосным, а разница охватывает 2016-02-29, но даже несмотря на то, что 3916 - високосный год, разница между двумя датами в марте в последовательных годах не превышает 3916 -02-29. Компонент «1 час» объясняется тем, что часовой пояс, в котором я нахожусь, США / Гора или Америка / Денвер (UT C -07: 00 в стандартное время, UT C -06: 00 в летнее время), переключается между зимним временем (стандартное время) и летним временем (летнее время) в воскресенье 3917-03-11 в 02:00. Обратите внимание, что strftime() предполагает местное время; использование gmtime() вместо localtime() изменяет видимые значения времени.

Попробуйте этот код на своем компьютере. Я ожидаю, что вы столкнулись с переполнением, потому что у вас 32-битная time_t и даты в четвертом тысячелетии переполнились. Я не удивлюсь, обнаружив, что mktime() возвращает -1 для обеих дат в первом (неоткорректированном) фрагменте, поскольку значения не могут быть точно представлены (а разница между -1 и -1 действительно 0) .

Если у вас есть 32-битные time_t значения, вы столкнетесь с проблемами после того, как значение time_t достигнет:

0x7FFFFFFF = 2147483647 = 2038-01-19 03:14:07Z (aka UTC)

На машине с 64-битной time_t нет столкнуться с этой проблемой.

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