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

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

我想以 ISO 8601 格式打印当前时间,尽可能接近 Python 的

isoformat()
函数,该函数会产生类似
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 posix strftime
1个回答
3
投票

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);
  off += snprintf(buf+off, 30-off, 
                  "%c%02ld:%02ld", 
                  local->tm_gmtoff >= 0 ? '+' : '-', 
                  labs(local->tm_gmtoff)/3600,
                  labs(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-16T16:18:12.161+01:00

TZ="America/Anchorage" ./a.out; 
using strftime: 2024-01-16T06:18:12.173-09:00

TZ="UTC" ./a.out
using strftime: 2024-01-16T15:18:12.184+00:00
© www.soinside.com 2019 - 2024. All rights reserved.