linux概念之时间与时区

时间:2024-04-21 12:03:58

http://www.cnblogs.com/liuyou/archive/2012/07/29/2614338.html

Linux时间基准

以上我们了解了RTC(实时时钟、硬件时钟)和OS时钟(系统时钟、软时钟)。下面我们具体描述OS时钟。OS时钟是由可编程定时/计数器产生的输出脉冲触发中断而产生的。输出脉冲的周期叫做一个“时钟滴答”。计算机中的时间是以时钟滴答为单位的,每一次时钟滴答,系统时间就会加1。操作系统根据当前时钟滴答的数目就可以得到以秒或毫秒等为单位的其他时间格式。

定义“时间基准”的目的是为了简化计算,这样计算机中的时间只要表示为从这个时间基准开始的时钟滴答数就可以了。“时间基准是由操作系统的设计者规定的。例如DOS的时间基准是1980年1月1日,Unix的时间基准是1970年1月1日上午12点,Linux的时间基准是1970年1月1日凌晨0点。

1. 时间和时区
如果有人问你说现在几点? 你看了看表回答他说晚上8点了. 这样回答看上去没有什么问题,但是如果问你的这个人在欧洲的话那么你的回答就会让他很疑惑,因为他那里还太阳当空呢.
这里就有产生了一个如何定义时间的问题. 因为在地球环绕太阳旋转的24个小时中,世界各地日出日落的时间是不一样的.所以我们才有划分时区(timezone) 的必要,也就是把全球划分成24个不同的时区. 所以我们可以把时间的定义理解为一个时间的值加上所在地的时区(注意这个所在地可以精确到城市)
地理课上我们都学过格林威治时间(GMT), 它也就是0时区时间. 但是我们在计算机中经常看到的是UTC. 它是Coordinated Universal Time的简写. 虽然可以认为UTC和GMT的值相等(误差相当之小),但是UTC已经被认定为是国际标准,所以我们都应该遵守标准只使用UTC
那么假如现在中国当地的时间是晚上8点的话,我们可以有下面两种表示方式
20:00 CST
12:00 UTC
这里的CST是Chinese Standard Time,也就是我们通常所说的北京时间了. 因为中国处在UTC+8时区,依次类推那么也就是12:00 UTC了.
为什么要说这些呢?
第一,不管通过任何渠道我们想要同步系统的时间,通常提供方只会给出UTC+0的时间值而不会提供时区(因为它不知道你在哪里).所以当我们设置系统时间的时候,设置好时区是首先要做的工作
第二,很多国家都有夏令时(我记得小时候中国也实行过一次),那就是在一年当中的某一天时钟拨快一小时(比如从UTC+8一下变成UTC+9了),那么同理到时候还要再拨慢回来.如果我们设置了正确的时区,当需要改变时间的时候系统就会自动替我们调整
现在我们就来看一下如何在Linux下设置时区,也就是time zone

2. 如何设置Linux Time Zone
在Linux下glibc提供了事先编译好的许多timezone文件, 他们就放在/usr/share/zoneinfo这个目录下,这里基本涵盖了大部分的国家和城市

# ls -F /usr/share/zoneinfo/
Africa/      Chile/   Factory    Iceland      Mexico/   posix/      Universal
America/     CST6CDT GB         Indian/      Mideast/ posixrules US/
Antarctica/ Cuba     GB-Eire    Iran         MST       PRC         UTC
Arctic/      EET      GMT        iso3166.tab MST7MDT   PST8PDT     WET
Asia/        Egypt    GMT0       Israel       Navajo    right/      W-SU
Atlantic/    Eire     GMT-0      Jamaica      NZ        ROC         zone.tab
Australia/   EST      GMT+0      Japan        NZ-CHAT   ROK         Zulu
Brazil/      EST5EDT Greenwich Kwajalein    Pacific/ Singapore
Canada/      Etc/     Hongkong   Libya        Poland    Turkey
CET          Europe/ HST        MET          Portugal UCT

在这里面我们就可以找到自己所在城市的time zone文件. 那么如果我们想查看对于每个time zone当前的时间我们可以用zdump命令

# zdump Hongkong
Hongkong Fri Jul 6 06:13:57 2007 HKT

那么我们又怎么来告诉系统我们所在time zone是哪个呢? 方法有很多,这里举出两种
第一个就是修改/etc/localtime这个文件,这个文件定义了我么所在的local time zone.
我们可以在/usr/share/zoneinfo下找到我们的time zone文件然后拷贝去到/etc/localtimezone(或者做个symbolic link)
假设我们现在的time zone是BST(也就是英国的夏令时间,UTC+1)

# date
Thu Jul 5 23:33:40 BST 2007我们想把time zone换成上海所在的时区就可以这么做

# cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# date
Fri Jul 6 06:35:52 CST 2007这样时区就改过来了(注意时间也做了相应的调整)
第二种方法也就设置TZ环境变量的值. 许多程序和命令都会用到这个变量的值. TZ的值可以有多种格式,最简单的设置方法就是使用tzselect命令

# tzselect
...

You can make this change permanent for yourself by appending the line
TZ='Asia/Hong_Kong'; (permission denied?) export TZ
to the file '.profile' in your home directory; then log out and log in again.

TZ变量的值会override /etc/localtime. 也就是说当TZ变量没有定义的时候系统才使用/etc/localtime来确定time zone. 所以你想永久修改time zone的话那么可以把TZ变量的设置写入/etc/profile里

说到设置时间这里还要明确另外一个概念就是在一台计算机上我们有两个时钟:一个称之为硬件时间时钟(RTC),还有一个称之为系统时钟(System Clock)
硬件时钟是指嵌在主板上的特殊的电路, 它的存在就是平时我们关机之后还可以计算时间的原因
系统时钟就是操作系统的kernel所用来计算时间的时钟. 它从1970年1月1日00:00:00 UTC时间到目前为止秒数总和的值 在Linux下系统时间在开机的时候会和硬件时间同步(synchronization),之后也就各自独立运行了
那么既然两个时钟独自运行,那么时间久了必然就会产生误差了,下面我们来看一个例子

[root@rac02 logs]# date
Thu Feb 26 12:09:14 CST 2015
[root@rac02 logs]# hwclock --show
Thu 26 Feb 2015 12:07:49 PM CST  -0.558829 seconds

通过hwclock --show命令我们可以查看机器上的硬件时间(always in local time zone), 我们可以看到它和系统时间还是有一定的误差的, 那么我们就需要把他们同步
# hwclock –hctosys  把硬件时间设置成系统时间
# hwclock –systohc  把系统时间设置成硬件时间
# hwclock --set --date="mm/dd/yy hh:mm:ss"   设置硬件时间我们可以开机的时候在BIOS里设定.也可以用hwclock命令
# date -s "dd/mm/yyyy hh:mm:ss" 修改系统时间用date命令就最简单了
现在我们知道了如何设置系统和硬件的时间. 但问题是如果这两个时间都不准确了怎么办? 那么我们就需要在互联网上找到一个可以提供我们准确时间的服务器然后通过一种协议来同步我们的系统时间,那么这个协议就是NTP了. 接下去我们所要说的同步就都是指系统时间和网络服务器之间的同步了

其实这个标题应该改为设置"NTP Relay Server"前的准备更加合适. 因为不论我们的计算机配置多好,运行时间久了都会产生误差,所以不足以给互联网上的其他服务器做NTP Server. 真正能够精确地测算时间的还是原子钟. 但由于原子钟十分的昂贵,只有少部分组织拥有, 他们连接到计算机之后就成了一台真正的NTP Server. 而我们所要做的就是连接到这些服务器上同步我们系统的时间,然后把我们自己的服务器做成NTP Relay Server再给互联网或者是局域网内的用户提供同步服务.

为了照顾到各地区的使用方便,又使其他地方的人容易将本地的时间换算到别的地方时间上去。有关国际会议决定将地球表面按经线从东到西,划成一个个区域,并且规定相邻区域的时间相差1小时。在同一区域内的东端和西端的人看到太阳升起的时间最多相差不过1小时。当人们跨过一个区域,就将自己的时钟校正1小时(向西减1小时,向东加1小时),跨过几个区域就加或减几小时。这样使用起来就很方便。现今全球共分为24个时区。由于实用上常常1个国家,或1个省份同时跨着2个或更多时区,为了照顾到行政上的方便,常将1个国家或1个省份划在一起。所以时区并不严格按南北直线来划分,而是按自然条件来划分。例如,中国幅员宽广,差不多跨5个时区,但为了使用方便简单,实际上在只用东八时区的标准时即北京时间为准。

1949年*成立后,这些时区在大陆不再采用。但国民*迁台后,仍维持采用1912年的时区划分,*地区的标准时间继续称为“中原标准时间”。中国首都北京位于东八区,东八区的标准时就是中国的标准时间。但中国的授时中心却建在全国大陆版图的几何中心点-陕西渭北。北京时间由中国科学院陕西天文台的原子钟确定,其误差率每30万年小于1秒。授时中心以BPM短波和BPL长波发出标准信号,各地的专用授时单位和广播电视系统以此为基准,校正自己的时钟后再公开向社会发布时间信息。

http://www.time.ac.cn/stime.asp  国家授时中心

Linux中为啥没有北京时区
偶然发现,使用Linux系统的设备中选择时区时,在下拉列表中没有北京,却有上海和重庆,还有乌鲁木齐。这是为什么呢?Cathayan对其进行了一番研究: 原因是1949年以前,中国一共分了5个时区,以哈尔滨、上海、重庆、乌鲁木齐和喀什为代表——分别是:长白时区GMT+8:30、中原标准时区 GMT+8、陇蜀时区GMT+7、新藏时区GMT+6和昆仑时区GMT+5:30。

1949年前 哈尔滨         上海           重庆          乌鲁木齐      喀什
对应地区 长白山GMT+8:30 中原标准时区GMT+8 陇蜀时区GMT+7 新藏时区GMT+6 昆仑时区GMT+5:30

如今windows系统,把北京、重庆、香港、乌鲁木齐归为一个时区了!
它是1912年北京观象台制订,后由内政部批准过....对于自己的城市不在列表中这个大问题,LinuxJournal(这是一本期刊杂志)也讲了怎么把自己的城市加入时区 列表的做法:到/usr/share/zoneinfo或/usr/lib/zoneinfo目录下,将Asia/Shanghai拷贝为Asia /Beijing,因为时区一样,数据也就一样。编辑zone.tab文件,还是找到刚才copy的城市再copy一行,只是其中的数字代表城市的经纬度,需要修改正确

Linux时钟分为系统时钟(System Clock)和硬件(Real Time Clock,简称RTC)时钟。系统时钟是指当前Linux Kernel中的时钟,而硬件时钟则是主板上由电池供电的时钟,这个硬件时钟可以在BIOS中进行设置。当Linux启动时,硬件时钟会去读取系统时钟的 设置,然后系统时钟就会独立于硬件运作。
Linux中的所有命令(包括函数)都是采用的系统时钟设置。在Linux中,用于时钟查看和设置的命令主要有date、hwclock。

1.tzselect                                                              //回车后会有选项提示
2.timeconfig                                                            //回车后会有选项界面(限于CentOS、Fedora系统)
3.TZ='Asia/Shanghai';export TZ                        //设置时区,并即时生效,'Asia/Shanghai'指亚洲的上海的时间(CST),其它的例如'Europe/London'英国伦敦时间(GMT,格林威治时间)
4.hwclock -w                                          //保存时区设置使之重启系统后仍生效(就是写入系统bios)。
其它:
5.linux时区配置查寻文件
/etc/sysconfig/clock                                  //由/etc/localtime定义而成?
6.linux时区配置文件
/etc/localtime                                        //修改该文件的方法是拷贝/usr/share/zoneinfo下的相应时区文件覆盖之(想把系统时区设置为哪个时区就把/usr/share/zoneinfo下对应的时区文件拷贝为/etc/localtime)

GMT(Greenwich Mean Time)代表格林尼治标准时间,这个大家都知道。
而CST却同时可以代表如下 4 个不同的时区:
    Central Standard Time (USA) UT-6:00
    Central Standard Time (Australia) UT+9:30
    China Standard Time UT+8:00
    Cuba Standard Time UT-4:00
可见,CST可以同时表示美国,澳大利亚,中国,古巴四个国家的标准时间。
前面提到的通过 Java 获取的CST时间用的是China Standard Time,而客户端JavaScript则默认采用的是美国的中部时间。
所以将 Fri Aug 28 09:37:46 CST 2009 加上 6 个小时,再加上 8 个小时,就等于 Fri Aug 28 2009 23:37:46 GMT+0800
可见,在以后的编程中为了避免错误,还是不要使用CST时间,而尽量采用GMT时间。

ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

今天在修改Linux的时区问题时遇到一个非常奇怪的问题,郁闷了一把。之前修改时区是直接使用下面的命令就ok的:
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
然而今天试却死活和自己的机器时间对不上,照理来说Asia/Shanghai的时区应该是GMT+8,刚好是中国的北京时间的。可通过date命令查看时间,总是差3个小时,然后google、百度一番,有的是修改/etc/sysconfig/clock文件,增加如下内容:
    ZONE="Asia/Shanghai"
    UTC=false
    结果仍然不起作用,然后使用tzselect命令选择时区,仍然无效。不死心,使用date -s命令指定时间,结果提示:
    date: cannot set date: Operation not permitted
    提示操作被禁止,仍无效。再又看到一个帖子,说是如果时区文件Asia/Shanghai的内容不是以GMT+8结尾的,改成GMT+8结尾就可以。然后赶紧查看Asia/Shanghai文件的内容,发现结尾是CST-8,惊喜了一把,以为找到解决方法了,结果改完后仍然无效。不过却看到GMT和CST时间的问题,赶紧google一番得到如下:
    GMT(Greenwich Mean Time,格林威治标准时间): 是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。
    UTC(Universal Time/Temps Cordonné 世界标准时间)
    CST(Central Standard Time 國家標準時間,一說中原標準時間); 中国标准时间(China Standard Time)
    GMT + 8 = UTC + 8 = CST
    这是几个时间的区别,然后也看到Asia/Shanghai这个时区文件的结尾是CST-8,一想肯定是标准时间惹的祸。再使用tzselect命令,注意选择第11项进行时间偏差的自定义设置,即自己指定TZ格式来设置时间,比如GST-11,设置完后系统会根据你的设置提示你当前时间是多少,如果不对就不确定,然后重复修改偏差设置直到满足你的要求即可。最终确定后,需要把TZ设置到profile文件中去,如下:
    # 修改当前用户的profile文件
    vi ~/.bash_profile
    # 增加时区设置
    TZ='CST-11'; export TZ
    # 保存profile文件后执行生效
    source ~/.bash_profile
    然后,通过date查看时间,ok了,可把我折腾了一番。说明下,我的系统是centos,如果linux系统不一样,可能处理方式不一样。

linux调整系统时区:
    找到相应的时区文件/usr/share/zoneinfo/Asia/Shanghai
    用这个文件替换当前的/etc/localtime文件
    这时date一下应该是CST时间了
    如果还不行,那就要修改一下TZ环境变量的值了。
    许多程序和命令都会用到这个变量的值,TZ的值可以有多种格式,最简单的设置方法就是使用tzselect命令或者终端输入TZ='CST-8'; export TZ就可以了。
    不过这个改变只在这次登陆生效,如果想要永久生效的话,就要把TZ='CST-8'; export TZ这两句添加到你的。profile文件里。
    Linux里确定系统时区先看TZ环境变量,如果TZ环境变量没有设置,然后再读取/etc/localtime文件来确定你的时区
    2)/etc/sysconfig/clock文件
    这个文件控制如何解读硬件时钟 (hardware clock)的时间。
    系统在启动的时候读取/etc/sysconfig/clock 文件的内容,根据这些内容调用hwclock 命令,来设置系统时钟。
    下面是转来的该文件配置项的解读:
    设定档案 /etc/sysconfig 控制如何解读由硬体时钟 (hardware clock) 的时间。

http://www.epochconverter.com/

UNIX时间又称POSIX时间/新纪元时间(Epoch Time):从协调世界时1970年1月1日0时0分0秒起到现在的总秒数,不包括闰秒。正值表示1970以後,负值则表示1970年以前。
Unix 2038 bug(Jason hatchet bug)
说到UNIX时间不得不提Unix 2038 bug(Jason hatchet bug):2038年1月19日3时14分07秒,32位元系统的UNIX时间将会被重置。
32
位的UNIX系统会以32位二进制数字表示时间,它们最多只能表示至协调世界时间2038年1月19日3时14分07秒(二进制:01111111
11111111 11111111 11111111),在下一秒二进制数字会是10000000 00000000 00000000
00000000,这是负数,因此各系统会把时间误解作1901年12月13日20时45分52秒(亦有说回归到1970年)。这时可能会令软件发生问
题,导致系统瘫痪。
目前解决方案是把系统由32位转为64位系统。在64位系统下,此时间最多可以表示到292,277,026,596年12月4日15时30分08秒。

UNIX及Linux的时间系统是由「新纪元时间」Epoch开始计算起,单位为秒,Epoch则是指定为1970年一月一日凌晨零点零分零秒,格林威治时间。
目前大部份的UNIX系统都是用32位元来记录时间,正值表示为1970以後,负值则表示1970年以前。我们可以很简单地计算出其时间领域:
2^31/86400(s) = 24855.13481(天) ~ 68.0958(年)
1970+68.0958 = 2038.0958
1970-68.0958 = 1901.9042
时间领域为[1901.9042,2038.0958]。

准确的时间为2038年一月十八日星期一晚上十点十四分七秒。那一刻,时间将会转为负数,变成1901年十二月十三日黑色星期五下午三点四十五分五十二秒,然後Jason就会跑出来用斧头砸掉您的电脑。
这就是所谓的UNIX 2038 BUG,或者您也可戏称为Jason hatchet bug。在大部份的UNIX上,并没有所谓Y2K问题,不过都有2038年问题。
在一些64位元的平台上,例如Digital Alpha、SGI、Sparc等等,则用64位元来表示时间。
2^63/86400 ~ 1E14(天) ~ 2.92E11(年)
大约是292亿年。
因此,使用64位元的电脑可能会有 Armageddon bug 的问题。届时位於猎户座旋臂的太阳,已经是黑矮星或暗黑物质,猎户座旋臂大概也已经被重力波震断,银河系大概则已经变成小型似星体了。
虽然许多人认为UNIX的2038年问题会随着科技的进步,而将电脑逐步汰换成64位元电脑,因此无须担心。但我个人相信,在2038年,依然会有许多状况出现。因为,就事实而言,目前许多UNIX系统都有足够的能力服役到2038年而毫无问题。因此,如果有意添购电脑主机,而且有预期会使用到那个时候,最好是选购64位元电脑,确认只有世界末日问题(除非您想要把资料流传给下一个宇宙,那就要另当别论了)。

UTC=true|yes|false|no - 指定硬体时钟的时间是格林威冶时间还是系统本地时间。true 或 yes 表示硬体时钟是使用格林威冶时间,其他则为本地时间。预设为本地时间。
    ARC=false|no - 指定硬体时钟是否 1980 epoch 时间 (一般使用 ARC 主控台的 Alpha 电脑使用的 epoch 时间)。false 或 no 表示使正常 UNIX epoch 时间 - 1970。预设使用正常 UNIX epoch 时间
    SRM=false|no - 指定硬体时钟是否 1900 epoch 时间 (一般使用 SRC 主控台的 Alpha 电脑使用的 epoch 时间)。false 或 no 表示使正常 UNIX epoch 时间 - 1970。预设使用正常 UNIX epoch 时间
    ZONE=时区 - 现时系统本地时区名称,只让时间日期属性工具 system-config-data 知道现时 /etc/localtime 所指的时区,改变其值并不会改变实际的系统时区。其值 必须为 /usr/share/zoneinfo 下的时区档案名称。
    这里提供一个该文件的配置:
    ZONE="Asia/Shanghai"
    UTC=false
    ARC=false
    注意:
    如果你原来的设置的硬体时钟时间是格林威治时间要记得更改这个命令之后,要记得用4)的方法把系统时间写入硬体时钟,否则,下次启动系统会把硬体时钟记录 的格林威治时间解读为Asia/Shanghai的当前时间。
    3)调整系统时间方法
    时间设定成2005年8月30日的命令如下:
    #date -s 08/30/2005
    将系统时间设定成下午6点40分0秒的命令如下。
    #date -s 18:40:00
    这里设置的时间只是设置了系统时间,系统下次重启之后,还是会从硬体时钟读取原来的时间,所以为了使时间设置生效就要使用4)的命令
    如果想要与标准时间同步的话就要使用ntpdate ,和NTP服务器做一个时间同步。同样,这里也要把同步后的系统时间利用4)的方法写入到硬体时钟。
    4)将系统时间写入硬件时钟COMOS
    可以使用clock或hwlock命令,也可以在BIOS里设置硬体时钟的时间。
    clock命令
    #clock –w
    hwlock命令
    # hwclock –systohc
    关于linux的系统时钟和硬体时钟:
    linux系统有两个时钟,一个是系统时钟,一个是硬体时钟(COMOS),硬体时钟就是主板上通过晶振计时的时钟,通常是由一块电池供电,一般能用三年 左右。
    Linux系统在启动时,会先读取硬体时钟,把硬体时钟的时间设置为当前的系统时间,之后,系统时间就和硬体时钟独立运行了。系统时钟由linux内核维 护,硬体时钟还是晶振控制。

计算机都有个计时电路,尽管一般使用“时钟”这个词来表示这些设备,但它们实际上并不是通常意义的时钟,把它们称为计时器(timer)可能更恰当一点。计算机的计时器通常是一个精密加工过的石英晶体,石英晶体在其张力限度内以一定的频率振荡,这种频率取决于晶体本身如何切割及其受到张力的大小。有两个寄存器与每个石英晶体相关联,一个计数器(counter)和一个保持寄存器(holdingregister)。石英晶体的每次振荡使计数器减1。当计数器减为0时,产生一个中断,计数器从保持寄存器中重新装入初始值。这种方法使得对一个计时器进行编程,令其每秒产生60次中断(或者以任何其它希望的频率产生中断)成为可能。每次中断称为一个时钟嘀嗒(clocktick)。

Linux 启动时,其中的一个脚本(/etc/rc.d/rc.sysinit)会运行 /sbin/hwclock 程序,把当前的硬件时钟复制为系统 时间。hwclock 假定硬件时钟已经设置为本地时钟,除非带有 –utc 参数。脚本文件会读取 /etc/sysconfig/clock 文 件的设置,因此我们不需要修改脚本,直接修改这个配置文件就可以了,根据需要把其中的 UTC 行,设置为 true 或 者 false。
在VMware中执行挂起操作后,时间也跟着停止了,当再次开启Guest系统时,时间确实上次挂起的时间,此时可以使用"hwclock -s"命令来同步到当前的时间。
[root@Server huage]# date
Sat Jun 11 19:19:08 CST 2011
[root@Server huage]# hwclock
Tue 14 Jun 2011 03:59:21 PM CST  -0.709332 seconds
[root@Server huage]# hwclock -s           //将系统的时间同步到BIOS中的时间
[root@Server huage]# date
Tue Jun 14 15:59:28 CST 2011

http://www.time.ac.cn/times/timefairy.htm

大家都知道计算机电脑的时间是由一块电池供电保持的,而且准确度比较差经常出现走时不准的时候。通过互联网络上发布的一些公用网络时间服务器NTP server,就可以实现自动、定期的同步本机标准时间。
依靠windows系统默认的windows或NIST等*的时间服务器同步时间,总存在着访问堵塞、时间延迟大(同步精度低)等因素的影响。现在中国的国家授时中心发布了一个时间服务器地址,大家可以用国人自己的标准时间  !

中国国家授时中心:  http://www.time.ac.cn/stime.asp
需要启动Windows Time服务,才可以自动同步。也可以不手动开服务,在时间日期里同步时会自动开启服务,win7下测试通过。