C API在指定时区返回时间字符串?

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

有这样的API吗?

POSIX指定tzset()

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

所以,理论上可以使用这样的东西将t0 (a time_t )转换为US / Eastern时间,而不是默认的TZ:

 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()再次查看它。

在实践中,这可能会或可能不会起作用; 这取决于系统。

如果你需要这些东西的线程安全版本,你将不得不更加努力。 这绝对不是编写的线程安全的。

示例代码在错误检查方面受到了限制 – 它没有任何错误检查。

我永远不会声称这是一种简单的方法; 应该有更好的方法。

测试代码

 #include  #include  #include  #include  #include  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) 

请注意,当EST和PST的字符串没有指定夏令时代码时,您将获得一个时区偏移量; 如果设置了夏令时代码(例如"EST5EDT""PST8PDT" )并且打印时间是在一年中的适当时间(例如4月底),则会打印出EDT或PDT时间值。

另请注意,有关如何处理时区的ISO标准存在冲突。 ISO 8601(日期/时间格式)表示UTC(格林威治)以东的时区为正,而UTC以西的时区为负。 至少一些其他标准(例如SQL,ISO 9075)使用相同的表示法。 另一方面,POSIX(又名ISO 9945)在TZ中使用相反的约定,如示例代码所示。 只有长期存在的先例才能接受冲突。 C标准没有提及TZ环境变量的格式(或存在)(尽管C99§7.23.3.5strftime 函数多次引用ISO 8601)。

而且(正如有用的提醒为什么错误检查是一个好主意),在Mac OS X 10.7.3上,我的环境中没有设置TZ(但它通常是美国/太平洋地区,又名Cupertino,又名America / Los_Angeles , 时间)。 因此,当getenv()返回空指针时,上面的代码崩溃了。 我在环境中使用TZ=CST6CDT运行它,正如您从第一行输出中看到的那样。

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

您可以将其转换为struct tm ,将时间戳分解为实际的日期和时间 – 年,月,日,小时,分钟和秒。 转换有两个函数: gmtime ,它将其gmtime为UTC样式时间(即格林威治时区)。 另一个是localtime ,它将环境转换为环境配置为相信代表机器位置的任何时区。

下一步是使用strftime将其转换为可读的东西。 这是基于当前的语言环境,所以(例如)当我写这个时,它就是我所说的“星期日”。 但是,如果我的机器配置为西class牙语,则可能会显示为“Domingo”,或者该订单上的某些内容。

你真的有两个相当不同的问题。 您只能将time_t转换为两个时区之一的时间:“本地”时区(至少,无论机器配置为“本地”),还是格林威治时间。 如果你想要任何其他时区,你几乎要坚持转换到GM时间,然后调整到你选择的时区。

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