C API是否返回指定时区中的时间字符串?

C API是否返回指定时区中的时间字符串?,c,timezone,C,Timezone,在C语言中,是否有任何API可以将time()函数返回的时间转换为特定的时区? 有一个函数strftime(),可将其转换为系统的当前时区。 但我想要的是函数输入是时间(由time()返回)和时区,它将以所述时区格式转换特定的格式化时间 有这样的API吗?这里有三个步骤要看。首先,time\u t表示绝对时间戳——至少在概念上是UTC时间戳的顺序。它(通常)不在任何特定的时区——它通常表示自某个纪元(通常是1970年1月1日午夜)以来的秒数 您可以将其转换为struct tm,它将时间戳分解为实

在C语言中,是否有任何API可以将
time()
函数返回的时间转换为特定的时区? 有一个函数
strftime()
,可将其转换为系统的当前时区。 但我想要的是函数输入是时间(由
time()
返回)和时区,它将以所述时区格式转换特定的格式化时间


有这样的API吗?

这里有三个步骤要看。首先,
time\u t
表示绝对时间戳——至少在概念上是UTC时间戳的顺序。它(通常)不在任何特定的时区——它通常表示自某个纪元(通常是1970年1月1日午夜)以来的秒数

您可以将其转换为
struct tm
,它将时间戳分解为实际的日期和时间——年、月、日、小时、分钟和秒。有两个函数可以进行这种转换:
gmtime
,它保留UTC风格的时间(即格林威治时区)。另一个是
localtime
,它将其转换为环境配置为表示机器位置的任何时区

下一步是使用strftime将其转换为可读的内容。这是基于当前的语言环境,所以(例如)当我写这篇文章时,我认为它是“星期天”。但是,如果我的机器配置为西班牙语,那么可能会显示为“Domingo”或类似命令

你真的有两个完全不同的问题。您只能将
时间\u t
转换为两个时区之一的时间:“本地”时区(至少,机器配置为“本地”的任何时区)或格林威治时间。如果你想要任何其他时区,你会被一些东西卡住,比如转换为通用时间,然后调整到你选择的时区

对于调整格式有更多的规定。默认情况下,库将始终转换为“C”语言环境,这几乎是美国英语的简化版本。您还可以设置匿名区域设置(“”),该区域设置将为您提供与机器配置方式相匹配的区域设置。作为第三种选择,大多数库都允许您指定特定区域的名称,因此如果您希望将日期格式化为加拿大法语区的某个人所期望的格式,您可以将区域设置为类似“French_Canada”的名称,这就是您得到的结果(虽然您使用的字符串随标准库的不同而不同,因此您可能需要使用类似“fr can”的字符串来代替)。

POSIX指定:

tzset()
函数应使用环境变量TZ的值来设置由
ctime
localtime
mktime
strftime
使用的时间转换信息。如果TZ不在环境中,则应使用实现定义的默认时区信息

因此,理论上,你可以使用类似这样的方法将
t0
(a
time\u t
)转换为美国/东部时间,如果这不是你的默认时间:

char old_tz[64];
strcpy(old_tz, getenv("TZ"));
setenv("TZ", "EST5", 1);
tzset();
struct tm *lt = localtime(&t0);
char buffer[64];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", lt);
setenv("TZ", old_tz, 1);
tzset();
这保留了一个旧时区的副本(你不能指望它在你使用这些东西时不会改变或超出范围),然后在环境中设置目标时区。然后,它告诉系统查看$TZ并相应地设置本地时区。然后使用
localtime()将给定的
time\t
值转换为细分的本地时间
,格式化字符串,然后重置TZ环境变量,并告诉系统再次使用
tzset()
查看它

实际上,这可能有效,也可能无效;这取决于系统

如果你需要这个东西的线程安全版本,你必须更加努力。这绝对不是书面的线程安全

示例代码略过了错误检查——它没有任何错误检查

我决不会说这是一种简单的方法;应该有更好的方法

测试代码 请注意,当EST和PST的字符串没有指定夏令时代码时,您将获得一个时区偏移;当设置了夏令时代码(例如
“EST5EDT”
“PST8PDT”
)并且打印时间在一年中的适当时间(例如四月底),您可以打印EDT或PDT时间值

还要注意的是,在如何处理时区方面存在相互冲突的ISO标准。ISO 8601(日期/时间格式)规定UTC以东(格林威治)的时区为正,UTC以西的时区为负。至少其他一些标准(例如SQL、ISO 9075)使用相同的符号。另一方面,POSIX(又名ISO 9945)在TZ中使用相反的约定,如示例代码所示。冲突仅因长期存在的先例而被接受。C标准对TZ环境变量的格式(或存在性)保持沉默(尽管C99§7.23.3.5
strftime
函数多次引用ISO 8601)


在Mac OS X 10.7.3上,我的环境中没有设置TZ(但通常是US/Pacific,又名Cupertino,又名America/Los_Angeles,time)。因此当
getenv()时,上面的代码崩溃
返回一个空指针。我在环境中使用
TZ=CST6CDT
运行它,正如您从输出的第一行看到的那样。

是否
localtime
strftime
没有帮助?@keety:
localtime()
plus
strftime()
如果您当前的时区是IST(UTC+5:30),则没有帮助但是您希望时间以EST(美国/东部或UTC-5:00)打印。感谢Jonathan的详细回复。我有了这个想法,我需要它的线程安全逻辑。我会处理这个问题。时间API不是线程安全的,句号。嗯,
strftime()
可以,但是
localtime()
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> static void time_convert(time_t t0, char const *tz_value) { char old_tz[64]; strcpy(old_tz, getenv("TZ")); setenv("TZ", tz_value, 1); tzset(); char new_tz[64]; strcpy(new_tz, getenv("TZ")); char buffer[64]; struct tm *lt = localtime(&t0); strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", lt); setenv("TZ", old_tz, 1); tzset(); printf("%ld = %s (TZ=%s)\n", (long)t0, buffer, new_tz); } int main(void) { time_t t0 = time(0); char *tz = getenv("TZ"); time_convert(t0, tz); time_convert(t0, "UTC0"); time_convert(t0, "IST-5:30"); time_convert(t0, "EST5"); time_convert(t0, "EST5EDT"); time_convert(t0, "PST8"); time_convert(t0, "PST8PDT"); }
1335761328 = 2012-04-29 23:48:48 (TZ=CST6CDT)
1335761328 = 2012-04-30 04:48:48 (TZ=UTC0)
1335761328 = 2012-04-30 10:18:48 (TZ=IST-5:30)
1335761328 = 2012-04-29 23:48:48 (TZ=EST5)
1335761328 = 2012-04-30 00:48:48 (TZ=EST5EDT)
1335761328 = 2012-04-29 20:48:48 (TZ=PST8)
1335761328 = 2012-04-29 21:48:48 (TZ=PST8PDT)