C strptime和mktime错误的时间戳

s5a0g9ez  于 2023-05-06  发布在  其他
关注(0)|答案(2)|浏览(189)

我使用以下命令从文本文件中解析日期时间:

#define DATETIME_FORMAT "%Y-%m-%d %H:%M:%S"
if (!strptime(datetimestr, DATETIME_FORMAT, &record->datetime)) {
    return 0;
  } else {
    record->message_size = strlen(messagestr) - 1;
    messagestr[record->message_size] = '\0';
    strcpy(record->message, messagestr);
    printf("parsed '%s' '%s' %ld\n", messagestr, datetimestr, mktime(&record->datetime));
    return 1;
  }

我得到了这些指纹

parsed 'ETC' '2023-04-03 09:00:19' 1680508819
parsed 'StandUp' '2023-04-03 09:00:47' 1680508847
parsed 'Stop' '2023-04-03 09:11:55' 1680505915

但是当我将它们粘贴到online epoch converter时,我得到了:

  • 1680508819 =〉GMT:周一3.四月2023 8:00:19
  • 1680508847 =〉GMT:周一3.四月2023 8:00:47
  • 1680505915 =〉GMT:周一3.四月2023 7:11:55

那么,为什么strptimemktime转换第三次约会完全不同呢?

68de4m5k

68de4m5k1#

为什么strptime和mktime转换第三次约会完全不同?
struct tm未完全分配时,mktime()可能会出现不一致的行为。
strptime(datetimestr, DATETIME_FORMAT, &record->datetime)填充record->datetimestruct tm成员中的 * 一些 *。tm should be initialized before the call.
mktime()使用由strptime(..., %Y-%m-%d %H:%M:%S", ...分配的成员以及包括.tm_isdst在内的其他成员,这些成员占用一个小时。
strptime()之前,对整个struct tm进行零填充 *1,并将.tm_isdst设置为-1(让mktime()确定DST设置)。联系我们

// Add
memset(&record->datetime, 0, sizeof record->datetime);
record->datetime.tm_isdst = -1;

if (!strptime(datetimestr, DATETIME_FORMAT, &record->datetime)) {
  ...
  printf("parsed '%s' '%s' %lld\n", 
      messagestr, datetimestr, (long long) mktime(&record->datetime));

旁白:使用匹配的打印说明符。"%ld"可能不匹配time_t。建议转换为宽类型。
请注意,mktime()struct tm读取为 * 本地 * 时间,而不是GMT或UTC

  • 1详细信息:struct tm * 至少 * 9个成员。2(.tm_yday.tm_wday)在确定返回time_t时被gmtime()忽略。由于各种实现可能有超过9个标准成员,因此我们希望初始化/分配 * 所有 * 成员以获得一致的结果。

struct tm tm = { 0 };memset(&tm, 0, sizeof tm);是两种方法。
strptime(datetimestr, %Y-%m-%d %H:%M:%S", &record->datetime)设置6个预期成员(以及.tm_yday.tm_wday),但不设置.tm_isdst,也不可能设置其他tm成员。
代码可以零初始化并设置.tm_isdst

struct tm tm = { .tm_isdst = -1 };

代码可以用 * 复合文字 * 分配.tm_isdst和零个其他成员。

record->datetime = (struct tm){ .tm_isdst = -1 };
cs7cruho

cs7cruho2#

1.初始化struct tm

  1. strptime()返回NULL或指向解析器停止位置的指针。如果它是NULL或者它没有指向\0,那么可能是一个错误。
    1.修剪messagestr最后一个字符的方式是有问题的。如果要修剪换行符,请使用messagestr[strcspn(messagestr, "\n")] = '\0';
    我无法用以下最小的例子来重现你的发现。请让我知道你使用的是什么时区(TZ),以及最后一个日期时间字符串的结果。
#define _XOPEN_SOURCE
#include <stdio.h>
#include <time.h>

#define DATETIME_FORMAT "%Y-%m-%d %H:%M:%S"

int main(void) {
    char *dts[] = {
        "2023-04-03 09:00:19",
        "2023-04-03 09:00:47",
        "2023-04-03 09:11:55"
    };
    for(size_t i = 0; i < sizeof dts / sizeof *dts; i++) {
        struct tm tm = {0};
        char *s = strptime(dts[i], DATETIME_FORMAT, &tm);
        if(!s || *s) {
            printf("'%s' failed\n", dts[i]);
            continue;
        }
        printf("'%s' %ld\n", dts[i], mktime(&tm));
    }
}

下面是相应的输出:

'2023-04-03 09:00:19' 1680526819
'2023-04-03 09:00:47' 1680526847
'2023-04-03 09:11:55' 1680527515

相关问题