识别在 FreeBSD 中设置的当前默认时区

Bas*_*que 3 freebsd timezone

我知道sudo tzsetup会提示我更改 FreeBSD 上的时区设置。

? 如何在不进行更改的情况下查看当前时区设置?

我知道date显示我当前时间。例如:

UTC 2018 年 12 月 9 日星期日 05:45:25

...我假设当前的默认时区是 UTC。

但在这种情况下:

太平洋标准时间 2018 年 12 月 8 日星期六 21:52:04

PST不是一个真正的时区。这种 2-4 个字母的代码既不标准化也不唯一。真正的时区采用Continent/Region诸如Europe/Africaor之类的格式Africa/Tunis(请参阅Wikipedia)。

如何查看设置为默认值的真实时区?

这篇文章提到使用环境变量TZ

export TZ=America/Los_Angeles
Run Code Online (Sandbox Code Playgroud)

但是我的 FreeBSD 11.2 机器没有这样的变量集。所以我怀疑这不是驱动因素。

Cla*_*sen 5

TLDR 的答案是:

$ POSIXTZ=$(tail -n1 /etc/localtime)
$ echo $POSIXTZ
CET-1CEST,M3.5.0,M10.5.0/3

$ TZNAME=$(find /usr/share/zoneinfo | while read fname; do cmp -s /etc/localtime "$fname" && echo "$fname" | cut -c 21- ; done)
$ echo $TZNAME
Europe/Copenhagen
Run Code Online (Sandbox Code Playgroud)

当前时区存储在文件中/etc/localtime。正如@Kusalananda 所说,这可以是一个符号链接。但正如@JdeBP 暗示的那样,在 FreeBSD 上,这个文件通常是/usr/share/zoneinfo在安装过程中复制的。

这些文件源自contrib/tzdata 中的文本描述

然后,该信息被编译成二进制格式使用ZIC和格式在指定的tzfile

我不知道直接解析此文件的内置实用程序。但是使用 C 语言编写手头的文档应该很容易。如果我们想坚持开箱即用的内容,我们可以使用hexdump.

hexdump -v -C /etc/localtime
Run Code Online (Sandbox Code Playgroud)

或者,如果我们只想查看魔术标记:

$ hexdump -v -s 0 -n 5 -e '1/5 "%s\n"' /etc/localtime
TZif2
Run Code Online (Sandbox Code Playgroud)

或字段:

tzh_ttisgmtcnt  The number  of UTC/local indicators stored in the file.
tzh_ttisstdcnt  The number  of standard/wall indicators stored in the file.
tzh_leapcnt     The number  of leap seconds for which data is stored in the file.
tzh_timecnt     The number  of ``transition times'' for which data is stored in the file.
tzh_typecnt     The number  of ``local time types'' for which data is stored in the file (must not be zero).
tzh_charcnt     The number  of characters of ``time zone abbreviation strings'' stored in the file.
Run Code Online (Sandbox Code Playgroud)

使用:

hexdump -v -s 19 -n 4 -e '"tzh_ttisgmtcnt: " 1/4 "%9u\n"' /etc/localtime
hexdump -v -s 23 -n 4 -e '"tzh_ttisstdcnt: " 1/4 "%9u\n"' /etc/localtime
hexdump -v -s 27 -n 4 -e '"tzh_leapcnt:    " 1/4 "%9u\n"' /etc/localtime
hexdump -v -s 31 -n 4 -e '"tzh_timecnt:    " 1/4 "%9u\n"' /etc/localtime
hexdump -v -s 35 -n 4 -e '"tzh_typecnt:    " 1/4 "%9u\n"' /etc/localtime
hexdump -v -s 39 -n 4 -e '"tzh_charcnt:    " 1/4 "%9u\n"' /etc/localtime
Run Code Online (Sandbox Code Playgroud)

在我的情况下的结果:

tzh_ttisgmtcnt:         0
tzh_ttisstdcnt:         6
tzh_leapcnt:            6
tzh_timecnt:            0
tzh_typecnt:          133
tzh_charcnt:            6
Run Code Online (Sandbox Code Playgroud)

然后我们进行以下数学运算以找出第一个ttinfo开始的位置:

43 + (tzh_timecnt * 4) + (tzh_timecnt * 1)
43 + (0 * 4) + (0 * 1) = 43
Run Code Online (Sandbox Code Playgroud)

车轮缓缓落下:

$ hexdump -v -s 43 -n 6 -e '"ttinfo:\n tt_gmtoff:      " 1/4 "%9u\n tt_isdst:       " 1/1 "%1d\n tt_abbrind:     " 1/1 "%1u\n"' /etc/localtime
ttinfo:
 tt_gmtoff:      2350816009
 tt_isdst:       96
 tt_abbrind:     155
Run Code Online (Sandbox Code Playgroud)

有了这些数字,我可能有点不对劲。这确实是一种自虐的处理方式。所以我停止了使用tt_abbrind

但是如果我们查看tzfile规范的底部,我们会发现这个小块:

在第二个标头和数据之后是一个换行符包围的 POSIX-TZ-environment-variable-style 字符串,用于处理存储在文件中的最后一个转换时间之后的瞬间(如果没有 POSIX 表示,则换行符之间没有任何内容)对于这样的时刻)。

所以这很简单:

$ tail -n1 /etc/localtime
CET-1CEST,M3.5.0,M10.5.0/
Run Code Online (Sandbox Code Playgroud)

当您仔细观察时,您会发现/etc/localtime它不包含任何Continent/Region设置!但是当文件是从中复制时,/usr/share/zoneinfo您可以比较它们并找到可能的文件。我还没有深入确认是否/usr/share/zoneinfo可能包含重复项。但对我来说 - 这很好用:

$ find /usr/share/zoneinfo | while read fname; do cmp -s /etc/localtime "$fname" && echo "$fname" | cut -c 21- ; done
Europe/Copenhagen
Run Code Online (Sandbox Code Playgroud)

我们遍历所有文件/usr/share/zoneinfo并将它们与/etc/localtime. cmp使用该-s参数不会显示任何内容,只会使用值退出。如果值为零,我们将打印名称。打印名称时,我们cut用来删除前 21 个字符以获得Continent/Region