Linux:以大陆/城市形式获取时区的可靠方法

Linux:以大陆/城市形式获取时区的可靠方法

我正在寻找一种便携式/强大的方法来获取Linux机器(主要是不同版本的Debian)的时区,以大陆/城市的形式,例如欧洲/基辅。

到目前为止,我使用的是timedatectl status | grep zone | cut -d' ' -f10 这种方法的问题是它适用于 Debian 9,但不适用于 Debian 10(可以使用 docker 映像轻松检查)。

有没有更好、更通用/可移植的方法来做到这一点(更好的是无需刮擦/解析另一个命令的输出)?如果没有,我应该如何修改上面的命令,以便它在 Debian 9 和 10 上都有效。

答案1

timedatectl status | awk '/zone/ {print $3}'

答案2

地理时区名称既是抽象的又是方便的。在底层,时区数据文件是二进制文件,其中列出了偏移量、不连续性和 DST 更改,但没有列出位置(即使文件名指示了它,因此存在问题/etc/localtime)。有一个来自位置的映射和日期到时区偏移量,但它不是 1:1 – 例如,给定输出date,您无法轻松且确定地导出正在使用的地理位置(但您可以计算当前日期的一组兼容位置;或者您可以使用一些努力,检查较早的日期是否存在不连续性,以便推断出位置)。

有一个区域名称主列表和时区定义文件看起来像

# Zone  NAME            GMTOFF  RULES   FORMAT  [UNTIL]
Zone    Europe/London   -0:01:15 -      LMT     1847 Dec  1 0:00s
                         0:00   GB-Eire %s      1968 Oct 27
                         1:00   -       BST     1971 Oct 31 2:00u
                         0:00   GB-Eire %s      1996
                         0:00   EU      GMT/BST
Link    Europe/London   Europe/Jersey
Link    Europe/London   Europe/Guernsey
Link    Europe/London   Europe/Isle_of_Man

创建二进制Europe/London文件时,将处理指示的规则以构建时间规则(发生更改的时间戳,用 进行检查zdump -v Europe/London),并且相关位置会被别名。来自上述任何位置的文件内容或输出将无法区分 localtimedate

抽象可以让您及时处理法律变更,例如

# TZ=Europe/Andorra date -d "Aug 31 1984"
Fri Aug 31 00:00:00 CET 1984

TZ=Europe/Andorra date -d "Aug 31 1985"
Sat Aug 31 00:00:00 CEST 1985

(安道尔不在欧盟,但自 1985 年起遵循欧盟 DST 规则)

/etc/localtime是(二进制)时区数据文件,在 Debian 上,按照惯例,它应该是指向指定地理时区文件的符号链接(根据''拉紧''(9) 和《巴斯特》(10)localtime手册页:

/etc/localtime 文件配置本地系统的系统范围时区,应用程序使用该时区来呈现给用户。它应该是指向 /usr/share /zoneinfo/ 的绝对或相对符号链接,后跟时区标识符,例如“Europe/Berlin”或“Etc/UTC”。生成的链接应指向已配置时区的相应二进制 tzfile(5) 时区数据。

由于时区标识符是从 /etc/localtime 的符号链接目标名称中提取的,因此该文件可能不是普通文件或硬链接。

假设情况是这样:

if [ -L /etc/localtime ]; then
  IFS=/ read -a TZFILE < <(readlink -f /etc/localtime)
  printf -v TZNAME "%s/%s\n" ${TZFILE[-2]} ${TZFILE[-1]}
  echo $TZNAME
fi

在早期版本中(或者如果有人没有遵循文档)它是复制时区数据文件的。因此,为了验证这一点/etc/localtime/etc/timezone同意您需要比较它们

$ diff -s /etc/localtime /usr/share/zoneinfo/`cat /etc/timezone`
Files /etc/localtime and /usr/share/zoneinfo/America/New_York are identical

如果您需要倒退或彻底:

read CHECK file < <(sha256sum /etc/localtime)
while read sum file; do 
  [[ "$sum" == "$CHECK" ]] && printf "%s\n" "$file"
done < <(find /usr/share/zoneinfo/ -type f |xargs sha256sum)

这不是一个真正可移植的答案(POSIX 没有定义或要求这些长名字,它们来自 ICANN/IANA),并且您正在systemd这些版本的 Debian 上使用命令。

答案3

/etc/timezone您可以从文件中获取时区:

cat /etc/timezone

答案4

这在 Unix 和 Mac 机器上都很有效:

readlink /etc/localtime | awk -F'/' '{print $(NF-1)"/"$(NF)}'

相关内容