Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何撤消由TZ环境变量和tzset()函数引起的更改?_C - Fatal编程技术网

C 如何撤消由TZ环境变量和tzset()函数引起的更改?

C 如何撤消由TZ环境变量和tzset()函数引起的更改?,c,C,我有适用于特定时区的逻辑单元测试代码。理想情况下,单元测试可执行文件将始终以相同的行为运行,并与系统时区设置隔离 换句话说,如果系统时间是美国中部,则单元测试通过,但如果是亚洲/东京(例如),则单元测试失败,目标是使单元测试始终通过 我知道我可以使用setenv()或putenv()设置TZ环境变量,然后调用tzset()函数,这将根据新时区影响mktime()和localtime()的结果。您可以设置的示例如下: TZ的一般格式如下所述: 因此,可以使单元测试可执行文件具有mktime()

我有适用于特定时区的逻辑单元测试代码。理想情况下,单元测试可执行文件将始终以相同的行为运行,并与系统时区设置隔离

换句话说,如果系统时间是美国中部,则单元测试通过,但如果是亚洲/东京(例如),则单元测试失败,目标是使单元测试始终通过

我知道我可以使用
setenv()
putenv()
设置
TZ
环境变量,然后调用
tzset()
函数,这将根据新时区影响
mktime()
localtime()
的结果。您可以设置的示例如下:

TZ
的一般格式如下所述:

因此,可以使单元测试可执行文件具有
mktime()
localtime()
的行为,就像系统是
America/Chicago
,具有:
TZ=CST+6CDT,M3.2.0,M11.1.0
(DST开始于3月的第二个星期日,结束于11月的第一个星期日,标准偏移量为UTC-6)

同样的代码可以在Windows和Linux上运行

但是,当您在可执行文件中执行此操作时,它会影响整个代码中的所有
mktime()
localtime()
调用,以完成剩余的执行(而不仅仅是特定的测试)

我的问题是如何撤消更改,以便稍后执行的其他使用time.h local time函数的代码使用系统时间设置(例如日志消息中的时间戳)

互联网上有一些例子,可以围绕测试代码保存/恢复
TZ
环境变量。但是,如果
TZ
环境变量最初为空,该怎么办

有没有办法用当前系统时间设置的正确值填充
TZ
变量?或者更直接地说,是否有方法恢复由
TZ
tzset()引起的任何更改,然后返回到进程启动时的状态

如果没有POSIX/ANSIC方法,是否有任何特定于Windows和/或Linux的API来撤消更改

这是一个测试程序。它只需将
TZ
设置为空字符串,然后调用
tzset()
即可撤消Windows上的更改,但Linux上则不行

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#ifdef _WIN32
#include <Windows.h>
#endif

const char *Europe_Istanbul = "EET-2EEST,M3.5.0,M10.5.0";
const char *original_tz;

int set_env(const char *name, const char *value)
{
#ifdef _WIN32
    return _putenv_s(name, value == NULL ? "" : value);
#else
    if (value == NULL)
        return unsetenv(name);
    else
        return setenv(name, value, 1);
#endif
}

void log_time(time_t t)
{
    struct tm T;
    char timestamp[128] = "";
    T = *localtime(&t);
    strftime(timestamp, sizeof(timestamp), "%FT%T%z", &T);
    printf("%s\n", timestamp);
}

int main(void)
{
    time_t current_time = time(NULL);

    /* save TZ */
    original_tz = getenv("TZ");

    printf("TZ=%s\n", original_tz);

    log_time(current_time);

    set_env("TZ", Europe_Istanbul);
    tzset();

    log_time(current_time);

    /* restore TZ */
    set_env("TZ", original_tz);
    tzset();

    log_time(current_time);

    return 0;
}
Windows上的输出(带TZ)

Linux上的输出(无TZ):

Linux上的输出(带有TZ):


传统的C/Unix时区API有一个非常严重的基本限制。不,除了保存和恢复TZ并再次调用
tzset
之外,没有更好的方法了。您真正想要的是BSD
tzalloc
localtime\u rz
mktime\u z
函数。您可以
fork()
进行测试,但这有点极端,在不支持
fork()的系统上不起作用
。保存和恢复TZ的最大问题似乎是TZ最初可能根本没有设置。我认为(但我还没有证实)将TZ设置为“”等于根本没有设置TZ。或者,至少在Unix下,我非常确定有一种方法(尽管它可能不推荐使用/不标准)可以重置整个环境和/或删除/取消设置环境变量。您不能
old timezone=getenv()
+
setenv(新时区)
+执行此任务+
setenv(旧时区)
?TZ可以是空的吗?您说过将
TZ
设置为空字符串会撤消Windows上的更改,但我认为这是错误的。它试图将时区设置为操作系统设置的时区。在Linux上,它将时区设置为UTC。传统的C/Unix时区API存在一个非常严重的基本限制。不,除了保存和恢复TZ并再次调用
tzset
之外,没有更好的方法了。您真正想要的是BSD
tzalloc
localtime\u rz
mktime\u z
函数。您可以
fork()
进行测试,但这有点极端,在不支持
fork()的系统上不起作用
。保存和恢复TZ的最大问题似乎是TZ最初可能根本没有设置。我认为(但我还没有证实)将TZ设置为“”等于根本没有设置TZ。或者,至少在Unix下,我非常确定有一种方法(尽管它可能不推荐使用/不标准)可以重置整个环境和/或删除/取消设置环境变量。您不能
old timezone=getenv()
+
setenv(新时区)
+执行此任务+
setenv(旧时区)
?TZ可以是空的吗?您说过将
TZ
设置为空字符串会撤消Windows上的更改,但我认为这是错误的。它试图将时区设置为操作系统设置的时区。在Linux上,它将时区设置为UTC。
D:\>echo %TZ%
%TZ%

D:\>test_tz
TZ=(null)
2019-11-26T11:16:58-0600
2019-11-26T19:16:58+0200
2019-11-26T11:16:58-0600
D:\>set TZ=EST+5EDT,M3.2.0,M11.1.0

D:\>echo %TZ%
EST+5EDT,M3.2.0,M11.1.0

D:\>test_tz
TZ=EST+5EDT,M3.2.0,M11.1.0
2019-11-26T12:17:59-0500
2019-11-26T19:17:59+0200
2019-11-26T12:17:59-0500
[user@host dir]$ echo $TZ

[user@host dir]$ ./test_tz
TZ=(null)
2019-11-26T11:23:18-0600
2019-11-26T19:23:18+0200
2019-11-26T11:23:18-0600
[user@host dir]$ export TZ=EST+5EDT,M3.2.0,M11.1.0
[user@host dir]$ echo $TZ
EST+5EDT,M3.2.0,M11.1.0
[user@host dir]$ ./test_tz
TZ=EST+5EDT,M3.2.0,M11.1.0
2019-11-26T12:25:20-0500
2019-11-26T19:25:20+0200
2019-11-26T12:25:20-0500