Самый простой способ приблизиться к разнице отныне - прочитать даты из файла и разобрать их по месяцам, дням и годам (m, d, y
).Если вы не собираетесь проводить полную проверку каждой конверсии, то простой способ разделения четырехзначного года и двухзначного месяца и дня заключается в использовании fscanf
с соответствующим ширина поля модификаторы для ограничения преобразования до необходимого количества цифр, например
while (fscanf (fp, "%4d%2d%2d", &y, &m, &d) == 3) {
Тогда все, что нужно в цикле, это заполнить struct tm
значениями года, месяца и дня (не забывая вычесть 1900
от года, и установите каждый из часовых, минутных и вторых элементов равным нулю, а элемент летнего времени равен -1
).Простая функция может сделать это и вернуть time_t
после вызова mktime
, например
time_t fill_broken_down_time (int y, int m, int d)
{ /* initialize struct members */
struct tm bdt = { .tm_sec=0, .tm_min=0, .tm_hour=0, .tm_mday=d,
.tm_mon=m>0?m-1:0, .tm_year=y-1900, .tm_isdst=-1 };
return mktime(&bdt); /* return mktime conversion to time_t */
}
Чтобы закончить, все, что вам нужно, это получить значения time_t
и вызвать difftime
, чтобы получить разницув секундах между текущим временем и временем, считанным из файла как значение double
.Продолжая цикл в main()
, например,
while (fscanf (fp, "%4d%2d%2d", &y, &m, &d) == 3) {
time_t now = time(NULL),
then = fill_broken_down_time (y, m, d);
printf ("date[%d] %d/%d/%d is %.2f seconds from now.\n",
n++, m, d, y, difftime (now, then));
}
В целом, вы можете сделать что-то вроде:
#include <stdio.h>
#include <time.h>
time_t fill_broken_down_time (int y, int m, int d)
{ /* initialize struct members */
struct tm bdt = { .tm_sec=0, .tm_min=0, .tm_hour=0, .tm_mday=d,
.tm_mon=m>0?m-1:0, .tm_year=y-1900, .tm_isdst=-1 };
return mktime(&bdt); /* return mktime conversion to time_t */
}
int main (int argc, char **argv) {
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
int y, m, d, n = 1;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fscanf (fp, "%4d%2d%2d", &y, &m, &d) == 3) {
time_t now = time(NULL),
then = fill_broken_down_time (y, m, d);
printf ("date[%d] %d/%d/%d is %.2f seconds from now.\n",
n++, m, d, y, difftime (now, then));
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
( note: программа ожидаетимя файла для чтения дат в качестве первого аргумента программы (или программа будет читать из stdin
по умолчанию, если аргумент не указан))
Пример входного файла
$ cat dat/3dates.txt
20190101
20190304
20180922
Пример использования / Вывод
$ ./bin/time_from_now dat/3dates.txt
date[1] 1/1/2019 is 6300212.00 seconds from now.
date[2] 3/4/2019 is 943412.00 seconds from now.
date[3] 9/22/2018 is 15030212.00 seconds from now.
Редактировать для комментария Изменение формата входного файла
Если ваш файл данных действительноотличается от трех строк дат, которые вы изначально разместили в своем вопросе, и содержит строки заголовков перед информацией о дате, поэтому вам нужно будет прочитать, идентифицировать и обработать эти строки перед обработкой строки даты.Поскольку вы хотите выводить в днях, а не в секундах, вы просто делите количество секунд на 86400
, чтобы получить разницу во времени в днях.
Чтобы прочитать строки заголовка дескриптора, просто настройте чтение на чтениеВся строка за раз в буфер соответствующего размера.Объявленная константа достаточного размера, чтобы гарантировать, что ваш буфер будет достаточно большим, например,
#define MAXC 1024u /* if you need a constant, #define one (or more) */
...
int main (int argc, char **argv) {
...
char buf[MAXC]; /* buffer to hold each line read from file */
Тогда вы просто будете использовать sscanf
вместо fscanf
, чтобы выполнить точно такой же анализ информации из каждой строки.Если формат строки не удовлетворяет формату yyyymmdd
, вы знаете, что это не строка даты - обрабатывайте эти строки любым удобным способом (они просто выводятся в приведенном ниже примере с префиксом "non-date line: "
.
В сочетании с делением количества секунд с момента времени в файле на 86400
секунд в день ваш новый цикл чтения будет выглядеть следующим образом:
while (fgets (buf, MAXC, fp)) { /* read each line in file */
/* if line isn't a date line, just output line as non-date line */
if (sscanf (buf, "%4d%2d%2d", &y, &m, &d) != 3) {
printf ("non-date line: %s", buf);
continue;
}
time_t now = time(NULL),
then = fill_broken_down_time (y, m, d);
double secs = difftime (now, then); /* get seconds between dates */
printf ("date[%d] %02d/%02d/%04d is %11.2f sec (%g days) from now.\n",
n++, m, d, y, secs, secs / 86400.0);
}
Вы говорите:
"I am not able to open the file"
Программа ожидает, что вы предоставите имя файла для чтения в качестве первого аргумента программы, в противном случае программа будет читать из stdin
по умолчанию. Это означает, что вы должны указать имя файла для программы,например,
./yourprogram your_date_file
, или вы должны предоставить эти данные в stdin
, либо передав эту информацию в программу из вывода какой-либо другой программы, либо просто перенаправив файл в качестве ввода в stdin
, например
some_utility_making_dates | ./yourprogram
или
./yourprogram < your_date_file
С учетом всех изменений ваша программа будет выглядеть следующим образом:
#include <stdio.h>
#include <time.h>
#define MAXC 1024u /* if you need a constant, #define one (or more) */
time_t fill_broken_down_time (int y, int m, int d)
{ /* initialize struct members */
struct tm bdt = { .tm_sec=0, .tm_min=0, .tm_hour=0, .tm_mday=d,
.tm_mon=m>0?m-1:0, .tm_year=y-1900, .tm_isdst=-1 };
return mktime(&bdt); /* return mktime conversion to time_t */
}
int main (int argc, char **argv) {
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
int y, m, d, n = 1;
char buf[MAXC]; /* buffer to hold each line read from file */
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line in file */
/* if line isn't a date line, just output line as non-date line */
if (sscanf (buf, "%4d%2d%2d", &y, &m, &d) != 3) {
printf ("non-date line: %s", buf);
continue;
}
time_t now = time(NULL),
then = fill_broken_down_time (y, m, d);
double secs = difftime (now, then); /* get seconds between dates */
printf ("date[%d] %02d/%02d/%04d is %11.2f sec (%g days) from now.\n",
n++, m, d, y, secs, secs / 86400.0);
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Пример входного файла с заголовками
$ cat dat/3dates-w-headers.txt
This file contains dates to read and convert to days.
The file also contains this description and dates in the format:
yyyymmdd
20190101
20190304
20180922
Пример использования / вывода
$ ./bin/time_from_now2 dat/3dates-w-headers.txt
non-date line: This file contains dates to read and convert to days.
non-date line: The file also contains this description and dates in the format:
non-date line:
non-date line: yyyymmdd
date[1] 01/01/2019 is 6348645.00 sec (73.4797 days) from now.
date[2] 03/04/2019 is 991845.00 sec (11.4797 days) from now.
date[3] 09/22/2018 is 15078645.00 sec (174.521 days) from now.
Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.