如何使用 strftime 在 Linux 中将当前时间打印为 ISO 8601 字符串?

问题描述 投票:0回答:1

我想将当前时间打印为尽可能接近Python的isoformat()的ISO 8601

2024-01-16T09:32:46.090+01:00

目前我使用了以下使用 gettimeofday、localtime 和 strftime 的代码片段:

#include <stdio.h> //printf
#include <sys/time.h>

int main(){
  struct timeval tv; 
  struct timezone tz;

  gettimeofday(&tv, &tz);

  char buf[30]; // 29 chars + '\0'
  strftime(buf, 30, "%Y-%m-%dT%H:%M:%S%z", localtime(&tv.tv_sec));

  printf("using strftime: %s\n", buf);
}

生成

2024-01-16T09:32:46+01:00
(缺少毫秒)。

我在 strftime 中没有找到任何格式说明符来打印毫秒。

c linux strftime
1个回答
0
投票

strftime 采用 struct tm 作为输入,并且 struct tm 没有毫秒/微秒的概念,因此 strftime 无法从中获取毫秒。

为了获取毫秒,您需要求助于 gettimeofday 返回的 struct timeval,它有一个名为

tv_usec
的成员,其中的微秒可以通过除以 1000 轻松转换为毫秒。或者使用 clock_gettime 提供纳秒。请参阅底部带有 clock_gettime 的示例。

#include <stdio.h> //printf
#include <sys/time.h>

int main(){
  struct timeval tv; 
  struct timezone tz;

  gettimeofday(&tv, &tz);

  char buf[30]; // 29 chars + '\0'
  int off = 0;
  struct tm *local = localtime(&tv.tv_sec);
  off = strftime(buf, 30, "%Y-%m-%dT%H:%M:%S", local);
  off += snprintf(buf+off, 30-off, ".%03d", tv.tv_usec/1000);
  off += strftime(buf+off, 30-off, "%z", local);


  printf("using strftime: %s\n", buf);
}

执行时会产生

2024-01-16T14:08:15.079+0100
,它是带有毫秒和 UTC 偏移量的 ISO 8601。不幸的是,
%z
产生 UTC 偏移量,格式为
+0100
(无冒号),而不是
+01:00

gcc test.c -g -Wall -std=c11 && ./a.out
using strftime: 2024-01-16T14:08:15.079+0100

如果您确实需要带冒号的 UTC 偏移量。然后您可以使用

gettimeofday
中的 struct timezone。您需要将
off += strftime(buf+off, 30-off, "%z", local);
替换为更复杂的:

  if (tz.tz_minuteswest >= 0) {
    off += snprintf(buf+off, 30-off, "+%02d:%02d", tz.tz_minuteswest/60, tz.tz_minuteswest%60);
  } else {
    off += snprintf(buf+off, 30-off, "-%02d:%02d", -tz.tz_minuteswest/60, -tz.tz_minuteswest%60);
  }

请注意,gettimeofday被认为已被弃用,取而代之的是clock_gettime,因此完成这一切的最佳方法是:

#include <stdio.h> //printf
#include <sys/time.h>

int main(){
  struct timespec tp;
  clock_gettime(CLOCK_REALTIME, &tp);

  char buf[30]; // 29 chars + '\0'
  int off = 0;
  struct tm *local = localtime(&tp.tv_sec);
  off = strftime(buf, 30, "%Y-%m-%dT%H:%M:%S", local);
  off += snprintf(buf+off, 30-off, ".%03ld", tp.tv_nsec/1000000);
  if (local->tm_gmtoff >= 0) {
    off += snprintf(buf+off, 30-off, "+%02ld:%02ld", local->tm_gmtoff/3600, local->tm_gmtoff%3600);
  } else {
    off += snprintf(buf+off, 30-off, "-%02ld:%02ld", -local->tm_gmtoff/3600, -local->tm_gmtoff%3600);
  }

  printf("using strftime: %s\n", buf);
}

唯一的变化是使用 clock_gettime 而不是 gettimeofday 并使用 localtimestruct tm 中提供的时区信息作为

tm_gmtoff

gcc test.c -g -Wall -std=c11

TZ="Europe/Madrid" ./a.out
using strftime: 2024-01-16T14:47:56.928+01:00


TZ="America/Anchorage" ./a.out
using strftime: 2024-01-16T04:47:39.226-09:00
© www.soinside.com 2019 - 2024. All rights reserved.