Я подозреваю, что ваши проблемы являются следствием двух факторов:
- Вы не вычитаете 1900 из значений года, введенных пользователем, и не вычитаете 1 из номера месяца - см. C11 §7.27.1 компоненты времени для получения информации о немного странном кодировании для
tm_year
и tm_mon
элементов struct tm
. - Ваша система использует 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
нет столкнуться с этой проблемой.