我想以 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()
来打印毫秒。
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 并使用 localtime 在 struct 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