сценарий таков: я получаю дату и время в формате «ГГГГ-ММ-ДД ЧЧ: ММ: СС» с помощью libexif. Чтобы свести к минимуму затраты на экономию, я хочу преобразовать дату и время в метку времени unix или аналогичную, которая стоит только 64-битную или 32-битную. Есть ли явный способ с c?
как преобразовать дату и время в метку времени unix в c?
Ответы (6)
Вы можете попробовать комбинацию strptime и mktime
struct tm tm;
time_t epoch;
if ( strptime(timestamp, "%Y-%m-%d %H:%M:%S", &tm) != NULL )
epoch = mktime(&tm);
else
// badness
Conditional jump or move depends on uninitialised value(s)
с valgrind, см. тот же вопрос здесь: mktime - это моя вина"> stackoverflow.com/questions/9037631/. Установка структуры tm
all на ноль помогает.
- person Andre Kampling; 18.07.2017
timegm()
вместо mktime()
, чтобы избежать проблем с часовыми поясами.
- person Alexis Wilke; 01.04.2018
Преобразуйте каждую часть даты/времени в целое число, чтобы заполнить struct tm
, а затем преобразуйте его в time_t
, используя мквремя.
mktime()
часто является неправильной функцией, timegm()
, скорее всего, будет правильной. Он не будет учитывать часовой пояс.
- person Alexis Wilke; 01.04.2018
Вот проводное решение в коде c/pseudo, которое я только что взломал. Удачи!
char * runner = NULL;
char *string_orig = "YYYY-MM-DD HH:MM:SS";
time_t time = 0;
struct tm tmp;
use strstr(string_orig, "-") and atoi foreach
tmp->tm_year ..
tmp->tm_mon ..
tmp->tm_mday ..
tmp->tm_hour ..
tmp->tm_min ..
tmp->tm_sec ..
with *runner as help
time = mktime(&tm)
Что насчет sscanf?
struct tm tmVar;
char *strVar = "YYYY-MM-DD HH:MM:SS";
time_t timeVar;
if(sscanf(strVar, "%d-%d-%d %d:%d:%d", &tm.tm_year, /* the other fields */)==6)
timeVar = mktime(&tmVar);
else
// bad format
Вот готовый фрагмент, когда strptime недоступен:
#include <stddef.h>
#include <time.h>
#include <stdio.h>
time_t string_to_seconds(const char *timestamp_str)
{
struct tm tm;
time_t seconds;
int r;
if (timestamp_str == NULL) {
printf("null argument\n");
return (time_t)-1;
}
r = sscanf(timestamp_str, "%d-%d-%d %d:%d:%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
if (r != 6) {
printf("expected %d numbers scanned in %s\n", r, timestamp_str);
return (time_t)-1;
}
tm.tm_year -= 1900;
tm.tm_mon -= 1;
tm.tm_isdst = 0;
seconds = mktime(&tm);
if (seconds == (time_t)-1) {
printf("reading time from %s failed\n", timestamp_str);
}
return seconds;
}
Настройте себе строку в sscanf на то, что вам нужно. Чтобы игнорировать часовой пояс и всегда преобразовывать как GMT/UTC, вычтите timezone
(или _timezone
) из seconds
(глобальный timezone
определяется в time.h. Летнее время уже игнорируется путем обнуления поля tm_isdst
в tm
.
Linux поддерживает функцию getdate()
, что, на мой взгляд, более практично, чем прямой вызов strptime()
. Это связано с тем, что функция getdate()
автоматически проверяет для вас много форматов. Это эквивалентно вызову strptime()
с различными форматами, пока функция не заработает или не будут протестированы все форматы.
// setenv() should be called only once
setenv("DATEMSK", "/usr/share/myprog/datemsk.fmt", 0);
// convert a date
struct tm * t1(getdate("2018-03-31 14:35:46"));
if(t1 == nullptr) ...handle error...
time_t date1(timegm(t1));
// convert another date
struct tm * t2(getdate("03/31/2018 14:35:46"));
if(t2 == nullptr) ...handle error...
time_t date2(timegm(t2));
Примечание. timegm()
похож на mktime()
, за исключением того, что он игнорирует языковой стандарт и использует UTC. В большинстве случаев это правильный способ конвертировать ваши даты.
Файл datemsk.fmt должен включать по крайней мере эти два формата для поддержки вышеуказанных дат:
%Y-%b-%d %H:%M:%S
%b/%d/%Y %H:%M:%S
Количество поддерживаемых форматов не ограничено, хотя вам может не хотеться иметь слишком много. Это будет довольно медленно, если у вас слишком много форматов. Вы также можете динамически управлять своими форматами и вызывать strptime()
в цикле.
Linux также предлагает функцию getdate_r()
, которая является потокобезопасной.
Страница руководства: http://pubs.opengroup.org/onlinepubs/7908799/xsh/getdate.html