C API 用于返回指定时区的时间字符串



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

有这样的 API 吗?

POSIX 指定tzset()

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

因此,理论上您可以使用这样的东西将t0(time_t(转换为美国/东部时间,而这不是您的默认 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 <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)

请注意,当 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.5 strftime 函数确实多次引用 ISO 8601(。

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

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

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

下一步是使用strftime将其转换为可读的内容。这是基于当前的语言环境,所以(例如(当我写这篇文章时,这就是我认为的"星期日"。但是,如果我的机器配置为西班牙语,则可能会显示为"Domingo"或该顺序上的内容。

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

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

相关内容

  • 没有找到相关文章

最新更新