一文搞懂Linux时区设置、自定义时区文件

概念介绍

常说的 Linux 系统时钟有两个

  • 一个是硬件时钟(RTC),即BIOS时间,一般保存的是 GMT0 时间,没时区、夏令时的概念

  • 一个是当地时钟(LTC),即我们日常经常看到的时间,比如 date 命令获取的时间,一般是在 GMT 时间的基础上增加或者减去 0 ~ 12 小时

世界标准时间 (UTC)

Coordinated Universal Time,协调世界时,又称世界标准时间或世界协调时间,是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量接近于格林尼治标准时间

格林尼治标准时间 (GMT)

Greenwich MeanTime,格林尼治时间,又称格林尼治平均时间或格林尼治标准时间,旧译格林威治标准时间,GMT 是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。英国伦敦格林尼治定为 0° 经线开始的地方,地球每 15° 经度就被分为一个时区,共分为 24 个时区,相邻时区相差一小时;例:中国北京位于东八区,GMT 时间比北京时间慢 8 小时

补充:UTC 基本上等于 GMT,世界上所有国家的时间都是以此时间为基准

夏令时 (DST)

Daylight Saving Time,是一种为节约能源而人为规定地方时间的制度,在这一制度实行期间所采用的统一时间称为"夏令时间"

一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏令时的国家具体规定不同。目前全世界有近110个国家每年要实行夏令时

我国也曾经实行过夏令时,在1986年开始实行,取得了相当大的成效,每年省电相当于3个三峡,但是在6年后的1991年,考虑到多方面的因素,最终选择了取消这一制度。夏令时在中国实行了6年便停止实行,其实停止实行的原因一言蔽之就是:中国太大了。中国和英法等国相比,有两点最大的不同:一是国土面积不同,二是气候不同

设置时间

设置系统时间

/etc/localtime 这个文件是用来设置系统的时区的,将 /usr/share/zoneinfo/ 中相应的时区文件拷贝覆盖 /etc/localtime,即可修改时区设置(也可以通过软连接实现),这种修改对 date 命令是及时生效的

不论是 date 还是 hwclock 都会用到这个文件,会根据这个文件的时区设置来进行 UTC 和本地时间的换算

设置完时区之后,可以通过 date 命令来设置系统时间

设置硬件时间

设置完系统时间后,硬件 RTC 时间并没有变更,如果发生重启,系统时间又会恢复到原来的值,所以这里需要将系统时钟同步到 RTC 硬件中

通过 hwclock 命令可以完成相关的设置

世界时区代表

先来看一下不带夏令时的时区文件代表

时区 地区代表 时区文件
GMT-12:00 International Date Line West
国际日期变更线
Etc/GMT+12
GMT-11:00 Midway Island, Samoa
萨摩亚时间
Etc/GMT+11
GMT-10:00 Hawaii
夏威夷阿留申时间
Etc/GMT+10
GMT-09:30 Marquesas
马克萨斯时间
Etc/GMT+9.30 **
GMT-09:00 Alaska
阿拉斯加时间
Etc/GMT+9
GMT-08:00 Pacific Time (US & Canada)
太平洋时间
Etc/GMT+8
GMT-07:00 Arizona, Mountain America
北美山地时间
Etc/GMT+7
GMT-06:00 Central America
北美中部时间
Etc/GMT+6
GMT-05:00 Eastern Time (US & Canada)
北美东部时间
Etc/GMT+5
GMT-04:00 Atlantic Time (Canada)
大西洋时间
Etc/GMT+4
GMT-03:30 Newfoundland
纽芬兰时间
Etc/GMT+3.30 **
GMT-03:00 Brasilia
巴西利亚时间
Etc/GMT+3
GMT-02:00 Mid-Atlantic
大西洋中部时间
Etc/GMT+2
GMT-01:00 Azores
亚速尔群岛时间
Etc/GMT+1
GMT+00:00 Greenwich Mean Time :
Dublin, Edinburgh, Lisbon, London
格林尼治时间
Etc/GMT
Etc/GMT+0
Etc/GMT-0
Etc/GMT0
GMT+01:00 Amsterdam, Berlin, Bern,
Rome, Stockholm, Vienna
欧洲中部时间
Etc/GMT-1
GMT+02:00 Jerusalem
以色列时间
Etc/GMT-2
GMT+03:00 Moscow, St. Petersburg, Volgograd
莫斯科时间
Etc/GMT-3
GMT+03:30 Tehran
伊朗时间
Etc/GMT-3.30 **
GMT+04:00 Abu Dhabi, Muscat
海湾时间
Etc/GMT-4
GMT+04:30 Kabul
阿富汗时间
Etc/GMT-4.30 **
GMT+05:00 Islamabad, Karachi, Tashkent
巴基斯坦时间
Etc/GMT-5
GMT+05:30 Chennai, Kolkata, Mumbai, New Delhi
印度时间
Etc/GMT-5.30 **
GMT+05:45 Kathmandu
尼泊尔时间
Etc/GMT-5.45 **
GMT+06:00 Astana, Dhaka
孟加拉国时间
Etc/GMT-6
GMT+06:30 Yangon (Rangoon)
缅甸时间
Etc/GMT-6.30 **
GMT+07:00 Bangkok, Hanoi, Jakarta
印度支那时间
Etc/GMT-7
GMT+08:00 Beijing, Chongqing, Hong Kong, Urumqi
中国时间
Etc/GMT-8
GMT+08:30 Pyongyang
平壤时间
Etc/GMT-8.30 **
GMT+08:45 Eucla
澳大利亚中部西部时间
Etc/GMT-8.45 **
GMT+09:00 Osaka, Sapporo, Tokyo
日本时间
Etc/GMT-9
GMT+09:30 Adelaide
澳大利亚中央时间
Etc/GMT-9.30 **
GMT+10:00 Canberra, Melbourne, Sydney
澳大利亚东部时间
Etc/GMT-10
GMT+10:30 Lord Howe Island
豪勋爵时间
Etc/GMT-10.30 **
GMT+11:00 Magadan, Solomon Is., New Caledonia
所罗门群岛时间
Etc/GMT-11
GMT+12:00 Fiji, Kamchatka, Marshall Is.
斐济时间
新西兰时间
Etc/GMT-12
GMT+12:45 Chatham Is.
查塔姆岛标准时间
Etc/GMT-12.45 **
GMT+13:00 Nuku’alofa
汤加时间
Etc/GMT-13
GMT+14:00 Christmas Island
莱恩群岛时间
Etc/GMT-14

注意:

  • 带 ** 号的,表示默认不存在该时区文件,需自定义,详见后文的《自定义时区文件》章节
  • 表里说的时区文件,路径前缀都是 /usr/share/zoneinfo/

再来看一下带夏令时的时区文件代表

时区 地区代表 时区文件
GMT-12:00 International Date Line West
国际日期变更线
N/A
GMT-11:00 Midway Island, Samoa
萨摩亚时间
N/A
GMT-10:00 Hawaii
夏威夷阿留申时间
America/Adak
GMT-09:30 Marquesas
马克萨斯时间
N/A
GMT-09:00 Alaska
阿拉斯加时间
America/Anchorage
GMT-08:00 Pacific Time (US & Canada)
太平洋时间
America/Los_Angeles
GMT-07:00 Arizona, Mountain America
北美山地时间
America/Denver
GMT-06:00 Central America
北美中部时间
America/Chicago
GMT-05:00 Eastern Time (US & Canada)
北美东部时间
America/New_York
GMT-04:00 Atlantic Time (Canada)
大西洋时间
America/Halifax
GMT-03:30 Newfoundland
纽芬兰时间
America/St_Johns
GMT-03:00 Brasilia
巴西利亚时间
皮埃尔和密克隆群岛时间
America/Sao_Paulo
America/Miquelon
GMT-02:00 Mid-Atlantic
大西洋中部时间
N/A
GMT-01:00 Azores
亚速尔群岛时间
Atlantic/Azores
GMT+00:00 Greenwich Mean Time :
Dublin, Edinburgh, Lisbon, London
格林尼治时间
Europe/London
GMT+01:00 Amsterdam, Berlin, Bern,
Rome, Stockholm, Vienna
欧洲中部时间
Europe/Amsterdam
GMT+02:00 Jerusalem
以色列时间
欧洲东部时间
Asia/Jerusalem
Europe/Kiev
GMT+03:00 Moscow, St. Petersburg, Volgograd
莫斯科时间
N/A
GMT+03:30 Tehran
伊朗时间
Asia/Tehran
GMT+04:00 Abu Dhabi, Muscat
海湾时间
N/A
GMT+04:30 Kabul
阿富汗时间
N/A
GMT+05:00 Islamabad, Karachi, Tashkent
巴基斯坦时间
N/A
GMT+05:30 Chennai, Kolkata, Mumbai, New Delhi
印度时间
N/A
GMT+05:45 Kathmandu
尼泊尔时间
N/A
GMT+06:00 Astana, Dhaka
孟加拉国时间
N/A
GMT+06:30 Yangon (Rangoon)
缅甸时间
N/A
GMT+07:00 Bangkok, Hanoi, Jakarta
印度支那时间
N/A
GMT+08:00 Beijing, Chongqing, Hong Kong, Urumqi
中国时间
N/A
GMT+08:30 Pyongyang
平壤时间
N/A
GMT+08:45 Eucla
澳大利亚中部西部时间
N/A
GMT+09:00 Osaka, Sapporo, Tokyo
日本时间
N/A
GMT+09:30 Adelaide
澳大利亚中央时间
Australia/Adelaide
GMT+10:00 Canberra, Melbourne, Sydney
澳大利亚东部时间
Australia/Melbourne
GMT+10:30 Lord Howe Island
豪勋爵时间
Australia/Lord_Howe
GMT+11:00 Magadan, Solomon Is., New Caledonia
所罗门群岛时间
N/A
GMT+12:00 Fiji, Kamchatka, Marshall Is.
斐济时间
新西兰时间
Pacific/Auckland
GMT+12:45 Chatham Is.
查塔姆岛标准时间
Pacific/Chatham
GMT+13:00 Nuku’alofa
汤加时间
N/A
GMT+14:00 Christmas Island
莱恩群岛时间
N/A

注意:

  • N/A,表示该地区没有夏令时
  • 表里说的时区文件,路径前缀都是 /usr/share/zoneinfo/

工具介绍

常用的工具

  • zdump,以文本展示某个时区变化历史的工具
  • zic,时区编译器,可将时区定义的文本文件编译成二进制时区文件
  • tzselect,设置时区的工具

这两个工具,在 Ubuntu 18.04 的机器上,默认就有

编译

去官网:https://www.iana.org/time-zones 下载最新的 timezone 压缩包

一文搞懂Linux时区设置、自定义时区文件_第1张图片

在 Ubuntu 18.04 的机器上,执行如下步骤开始编译

lzip -d tzdb-2022g.tar.lz
tar -xf tzdb-2022g.tar
mkdir out
cd tzdb-2022g/
# TOPDIR 指定目录安装,否则会安装到系统的 /usr/share/zoneinfo/ 目录下
make TOPDIR=$PWD/../out install

编译完成后的安装目录结构如下

一文搞懂Linux时区设置、自定义时区文件_第2张图片

zdump

cd ../out/usr/bin/
./zdump -v ../share/zoneinfo/America/Los_Angeles
# 报错说: No such file or directory
# 使用 strace 来跟踪看看哪里出了问题
strace ./zdump -v ../share/zoneinfo/America/Los_Angeles
# 发现是 zdump 默认会把 $TOPDIR/usr/share/zoneinfo/ 带进来
# 所以我们只需要带 America/Los_Angeles 就可以了
./zdump -v America/Los_Angeles
# 就可以看到夏令时相关的信息啦,strace 真有用

# 后来研读 zdump.c 的代码,发现绝对路径也可以,第一个字符要是'/'
./zdump -v /home/xxx/out/usr/share/zoneinfo/America/Los_Angeles

zic

# 回到 tzdb-2022g 目录,当前目录就有之前编译生成的 zdump/zic 工具
# 新建个目录,拿"北美"这个文本文件,编译一下生成二进制时区文件
mkdir my_tz_file
./zic -d ./my_tz_file/ northamerica
# 生成的二进制时区文件都在这个新建的文件夹里了
# 再用 zdump 试一下
./zdump -v /home/xxx/tzdb-2022g/my_tz_file/America/Los_Angeles
# 也是没问题的,但有一点疑惑
# 我们自己生成的 Los_Angeles 文件,文件大小跟系统的有出入
ls -lh ./my_tz_file/America/Los_Angeles
# 1.3K
ls -lh /usr/share/zoneinfo/America/Los_Angeles
# 2.8K

# 仔细看 zic 的说明文档才发现,如果要跟系统的文件一样大,需要加 -b fat 参数
./zic -b fat -d ./my_tz_file/ northamerica
# 据说这个可以兼容老版本

tzselect

这个工具还是挺好玩的,通过命令行交互,可以列出世界各大板块的各个国家的各个主要城市,还能看到该城市使用的是哪个时区文件
一文搞懂Linux时区设置、自定义时区文件_第3张图片

自定义时区文件

由于实际需求,Linux 系统自带的时区文件无法满足需要,上面介绍的世界时区是带夏令时规则的,如果我们不想考虑夏令时,可以使用 /usr/share/zoneinfo/Etc 目录下的时区文件,但是发现该目录缺少了一些非整数的时区文件

从上面介绍的世界时区代表可知,世界上存在着一些特殊的非整数时区,罗列如下

GMT-09:30
GMT-03:30
GMT+03:30
GMT+04:30
GMT+05:30
GMT+05:45
GMT+06:30
GMT+08:30
GMT+08:45
GMT+09:30
GMT+10:30
GMT+12:45

所以需要我们手动编辑 tzdb-2022g 目录下的 etcetera 文本文件,添加一段,如下红框部分

需要注意的是,文本文件最后需要一行空白行结尾

一文搞懂Linux时区设置、自定义时区文件_第4张图片

再用 zic 编辑器生成对应的时区文件,就可以拿去用啦

mkdir my_tz_file_etc
./zic -b fat -d ./my_tz_file_etc/ etcetera

参考

https://blog.csdn.net/weixin_42099906/article/details/116556736

https://blog.csdn.net/q793145253/article/details/127152917

https://www.modb.pro/db/575850

https://www.cnbiancheng.com/?p=1631

https://www.iana.org/time-zones

http://www.shijian.cc/shiqu/ - - 可以对照时间,验证设置的时区文件准不准

附录

根据 tzselect 汇总了全球200多个国家或地区的时区文件,以及典型的城市代表(400多个),json 格式如下:

  • gmt 表示该城市使用的时区(没有夏令时)
  • dst 表示该城市夏令时(如果有的话)的时区文件

一文搞懂Linux时区设置、自定义时区文件_第5张图片
Africa.json 片段如下,想获取完整版的可私信笔者获取

{
	"countries" : [
		{
			"country" : "Algeria",
			"cities" : [
				{
					"city" : "Algiers",
					"gmt" : "Etc/GMT-1",
					"dst" : "Africa/Algiers"
				}
			]
		},
		{
			"country" : "Angola",
			"cities" : [
				{
					"city" : "Luanda",
					"gmt" : "Etc/GMT-1",
					"dst" : "Africa/Luanda"
				}
			]
		},
		{
			"country" : "Benin",
			"cities" : [
				{
					"city" : "Porto-Novo",
					"gmt" : "Etc/GMT-1",
					"dst" : "Africa/Porto-Novo"
				}
			]
		},
		{
			"country" : "Botswana",
			"cities" : [
				{
					"city" : "Gaborone",
					"gmt" : "Etc/GMT-2",
					"dst" : "Africa/Gaborone"
				}
			]
		},
		{
			"country" : "Burkina Faso",
			"cities" : [
				{
					"city" : "Ouagadougou",
					"gmt" : "Etc/GMT0",
					"dst" : "Africa/Ouagadougou"
				}
			]
		},
		{
			"country" : "Burundi",
			"cities" : [
				{
					"city" : "Bujumbura",
					"gmt" : "Etc/GMT-2",
					"dst" : "Africa/Bujumbura"
				}
			]
		},
		{
			"country" : "Cameroon",
			"cities" : [
				{
					"city" : "Douala",
					"gmt" : "Etc/GMT-1",
					"dst" : "Africa/Douala"
				}
			]
		},
		{
			"country" : "Central African Rep.",
			"cities" : [
				{
					"city" : "Bangui",
					"gmt" : "Etc/GMT-1",
					"dst" : "Africa/Bangui"
				}
			]
		},
		{
			"country" : "Chad",
			"cities" : [
				{
					"city" : "Ndjamena",
					"gmt" : "Etc/GMT-1",
					"dst" : "Africa/Ndjamena"
				}
			]
		},
		{
			"country" : "Congo (Dem. Rep.)",
			"cities" : [
				{
					"city" : "Lubumbashi",
					"gmt" : "Etc/GMT-2",
					"dst" : "Africa/Lubumbashi"
				},
				{
					"city" : "Kinshasa",
					"gmt" : "Etc/GMT-1",
					"dst" : "Africa/Kinshasa"
				}
			]
		},
		{
			"country" : "Congo (Rep.)",
			"cities" : [
				{
					"city" : "Brazzaville",
					"gmt" : "Etc/GMT-1",
					"dst" : "Africa/Brazzaville"
				}
			]
		}
	]
}

你可能感兴趣的:(嵌入式Linux,linux)