概念介绍
常说的 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 压缩包
在 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
编译完成后的安装目录结构如下
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 系统自带的时区文件无法满足需要,上面介绍的世界时区是带夏令时规则的,如果我们不想考虑夏令时,可以使用 /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 文本文件,添加一段,如下红框部分
需要注意的是,文本文件最后需要一行空白行结尾
再用 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/ - - 可以对照时间,验证设置的时区文件准不准