在Linux上,我需要找到当前配置的时区作为Olson位置.我希望我的(C或C++)代码可以移植到尽可能多的Linux系统.
例如.我住在伦敦,所以我现在的奥尔森位置是"欧洲/伦敦".我对时区ID 不感兴趣,比如"BST","EST"等等.
Debian和Ubuntu有一个/etc/timezone
包含这些信息的文件,但我认为我不能依赖那个文件,我可以吗?Gnome有一个函数oobs_time_config_get_timezone()
也返回正确的字符串,但我希望我的代码可以在没有Gnome的系统上运行.
那么,在Linux上获得当前配置的时区作为Olson位置的最佳通用方法是什么?
这是很难得到一个可靠的答案.依靠这样的事情/etc/timezone
可能是最好的选择.
(如其他答案中所建议的,变量tzname
和tm_zone
成员struct tm
通常包含缩写,例如GMT
/ BST
etc,而不是问题中请求的Olson时间字符串).
在基于Debian的系统(包括Ubuntu)上,/etc/timezone
是一个包含正确答案的文件.
在一些基于Redhat的系统(包括至少某些版本的CentOS,RHEL,Fedora)上,您可以使用readlink()on获取所需的信息/etc/localtime
,这是(例如)的符号链接/usr/share/zoneinfo/Europe/London
.
OpenBSD似乎使用与RedHat相同的方案.
但是,上述方法存在一些问题.该/usr/share/zoneinfo
目录还包含诸如GMT
和之类的文件GB
,因此用户可以将符号链接配置为指向那里.
此外,没有什么可以阻止用户在那里复制正确的时区文件而不是创建符号链接.
绕过它的一种可能性(似乎适用于Debian,RedHat和OpenBSD)是将/ etc/localtime文件的内容与/ usr/share/zoneinfo下的文件进行比较,看看哪些匹配:
eta:~% md5sum /etc/localtime 410c65079e6d14f4eedf50c19bd073f8 /etc/localtime eta:~% find /usr/share/zoneinfo -type f | xargs md5sum | grep 410c65079e6d14f4eedf50c19bd073f8 410c65079e6d14f4eedf50c19bd073f8 /usr/share/zoneinfo/Europe/London 410c65079e6d14f4eedf50c19bd073f8 /usr/share/zoneinfo/Europe/Belfast 410c65079e6d14f4eedf50c19bd073f8 /usr/share/zoneinfo/Europe/Guernsey 410c65079e6d14f4eedf50c19bd073f8 /usr/share/zoneinfo/Europe/Jersey 410c65079e6d14f4eedf50c19bd073f8 /usr/share/zoneinfo/Europe/Isle_of_Man ... ...
当然缺点是这会告诉你所有与当前时区相同的时区.(这意味着完全意义上的相同 - 不仅仅是"当前同时",而且"在系统知道的同一天"也总是在同一天改变它们的时钟".)
您最好的选择可能是结合上述方法:/etc/timezone
如果存在则使用; 否则尝试解析/etc/localtime
为符号链接; 如果失败,搜索匹配的时区定义文件; 如果失败了 - 放弃回家;-)
(而且我不知道上述任何一个是否适用于AIX ......)
这没有标准的 c或c ++功能.但是,GNU libc有一个扩展.它struct tm
有两个额外的成员:
long tm_gmtoff; /* Seconds east of UTC */ const char *tm_zone; /* Timezone abbreviation */
这意味着如果您使用填充a struct tm
(例如localtime
or gmtime
)的函数之一,则可以使用这些额外字段.这当然只有在您使用GNU libc(以及它的最新版本)时才会这样.
此外,许多系统都有一个int gettimeofday(struct timeval *tv, struct timezone *tz);
功能(POSIX),它将填写一个struct timezone
.这包含以下字段:
struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of DST correction */ };
不完全是你要求的,但关闭......
我一直在开发一个免费的开源C++ 11/14库,它只需一行代码即可解决这个问题:
std::cout << date::current_zone()->name() << '\n';
它适用于所有最新版本的Linux,macOS和Windows.对我来说,这个程序输出:
America/New_York
如果您下载此库,但它不起作用,欢迎使用错误报告.