如何在c中将DATETIME转换为Unix时间戳?

j1dl9f46  于 2022-09-21  发布在  Unix
关注(0)|答案(7)|浏览(186)

场景是:我使用libexif获取格式为“YYYY-MM-DD hh:mm:ss”的DateTime。为了将节省的成本降到最低,我想将日期时间转换为Unix时间戳或类似的格式,它只需要64位或32位。对于c,有什么显式的方法吗?

7xllpg7q

7xllpg7q1#

您可以尝试strptimemktime的组合

struct tm tm;
time_t epoch;
if ( strptime(timestamp, "%Y-%m-%d %H:%M:%S", &tm) != NULL )
  epoch = mktime(&tm);
else
  // badness
rbl8hiat

rbl8hiat2#

将日期/时间的每个部分转换为整数以填充struct tm,然后使用mktime将其转换为time_t

nhn9ugyo

nhn9ugyo3#

这是一个用c/伪代码编写的有线解决方案,我刚刚把它们拼凑在一起。祝好运!

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)
lxkprmvk

lxkprmvk4#

那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
46scxncf

46scxncf5#

当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 argumentn");
        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 %sn", 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 failedn", timestamp_str);
    }

    return seconds;
}

在sscanf中调整您自己的字符串以适应您的需要。要忽略时区并始终转换为GMT/UTC,请从seconds减去timezone(或_timezone)(在time.h中定义timezone全局。已通过将tmtm_isdst字段置零来忽略dst。

j9per5c4

j9per5c46#

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

lx0bsm1f

lx0bsm1f7#

对于任何使用GCC的人来说,以下代码对我来说都很有效:


# define YEAR_OFFSET 1900

struct tm* dt = (struct tm*)malloc(sizeof(struct tm));
char *strVar = "2022-08-13 23:09:47"; //! "YYYY-MM-DD HH:MM:SS"
time_t timeVar;
if(sscanf(strVar, "%d-%hhd-%hhd %hhd:%hhd:%hhd", &dt->tm_year, &dt->tm_mon, &dt->tm_mday, &dt->tm_hour, &dt->tm_min, &dt->tm_sec)==6)
{
    dt->tm_year -= YEAR_OFFSET;
    dt->tm_mon -= 1;
    timeVar = mktime(&tmVar);
}
else
    ;// bad format
free(dt);

相关问题