這里主要講述linux中時(shí)間和時(shí)區(qū)相關(guān)的原理。包括設(shè)置方法、配置敏晤、環(huán)境變量、以及庫(kù)函數(shù)缅茉,及應(yīng)用舉例嘴脾。
基本概念
系統(tǒng)時(shí)鐘和硬件時(shí)鐘
Linux時(shí)鐘分為系統(tǒng)時(shí)鐘 (System Clock)和硬件(Real Time Clock,簡(jiǎn)稱RTC)時(shí)鐘蔬墩。系統(tǒng)時(shí)鐘是指當(dāng)前Linux Kernel中的時(shí)鐘译打,而硬件時(shí)鐘則是主板上由電池供電的時(shí)鐘,這個(gè)硬件時(shí)鐘可以在BIOS中進(jìn)行設(shè)置筹我。當(dāng)Linux啟動(dòng)時(shí)扶平,硬件時(shí)鐘會(huì)去讀取系統(tǒng)時(shí)鐘的設(shè)置,然后系統(tǒng)時(shí)鐘就會(huì)獨(dú)立于硬件運(yùn)作蔬蕊。
硬件時(shí)間和系統(tǒng)時(shí)間的同步
重新啟動(dòng)系統(tǒng)结澄,硬件時(shí)間會(huì)讀取系統(tǒng)時(shí)間哥谷,實(shí)現(xiàn)同步,但是在不重新啟動(dòng)的時(shí)候麻献,需要用hwclock或clock命令實(shí)現(xiàn)同步们妥。
時(shí)間和時(shí)區(qū)
UTC:協(xié)調(diào)世界時(shí),又稱世界標(biāo)準(zhǔn)時(shí)間勉吻,簡(jiǎn)稱UTC监婶,從英文國(guó)際時(shí)間/法文協(xié)調(diào)時(shí)間”Universal Time/Temps Cordonné”而來(lái)。
時(shí)區(qū):反映與UTC的時(shí)差問(wèn)題齿桃,中國(guó)大陸惑惶、香港、澳門短纵、臺(tái)灣带污、蒙古國(guó)、新加坡香到、馬來(lái)西亞鱼冀、菲律賓、澳洲西部的時(shí)間與UTC的時(shí)差均為+8悠就,也就是UTC+8千绪。各個(gè)地區(qū)的時(shí)間都是UTC結(jié)合地區(qū)的時(shí)區(qū)信息得到的。
整個(gè)地球分為二十四時(shí)區(qū)梗脾,每個(gè)時(shí)區(qū)都有自己的本地時(shí)間荸型,他們的關(guān)系如下:
-
UTC時(shí)間 與 GMT時(shí)間
我們可以認(rèn)為格林威治時(shí)間就是時(shí)間協(xié)調(diào)時(shí)間(GMT = UTC),格林威治時(shí)間和UTC時(shí)間都用秒數(shù)來(lái)計(jì)算的藐唠。
-
UTC時(shí)間與本地時(shí)間
UTC + 時(shí)區(qū)差 = 本地時(shí)間
時(shí)區(qū)差東為正帆疟,西為負(fù)。
-
UTC與Unix時(shí)間戳
在計(jì)算機(jī)中看到的UTC時(shí)間都是從(1970年01月01日 0:00:00)開始計(jì)算秒數(shù)的宇立。所看到的UTC時(shí)間那就是從1970年這個(gè)時(shí)間點(diǎn)起到具體時(shí)間共有多少秒踪宠。 這個(gè)秒數(shù)就是Unix時(shí)間戳。
例如:
本地(北京)在東八區(qū)妈嘹, 東八區(qū)時(shí)區(qū)差記為 +0800柳琢,則:本地(北京)時(shí)間 = UTC + (+0800)
所以,不同地區(qū)润脸, 其本地時(shí)間各不相同柬脸。
再如, 對(duì)于中國(guó)和格林毙驯,這兩個(gè)地區(qū)的時(shí)區(qū)不同倒堕,得到的時(shí)間也不同。分別如下:
CST:中國(guó)標(biāo)準(zhǔn)時(shí)間(China Standard Time)爆价,與UTC時(shí)差為8,這個(gè)解釋可能是針對(duì)RedHat Linux垦巴。
GMT:格林尼治標(biāo)準(zhǔn)時(shí)間(舊譯格林威治平均時(shí)間或格林威治標(biāo)準(zhǔn)時(shí)間媳搪;英語(yǔ):Greenwich Mean Time,GMT)是指位于英國(guó)倫敦郊區(qū)的皇家格林尼治天文臺(tái)的標(biāo)準(zhǔn)時(shí)間骤宣,因?yàn)楸境踝游缇€被定義在通過(guò)那里的經(jīng)線秦爆。
常用命令
下面給出的是常見的命令,不同系統(tǒng)可能有不同的命令憔披。
有關(guān)系統(tǒng)時(shí)間的命令: data,ntpupdate
有關(guān)硬件時(shí)鐘的命令: hwclock/clock
時(shí)區(qū)相關(guān)命令: tzselect
配置文件與環(huán)境變量
時(shí)區(qū)信息一般首先從環(huán)境變量中去讀等限,如果沒(méi)有再?gòu)?/etc/TZ
等配置文件中去讀。
所涉及的配置文件和環(huán)境變量可能會(huì)根據(jù)系統(tǒng)有所不同芬膝,一般情況如下:
時(shí)區(qū)的配置文件: etc/localtime (可以是/usr/share/zoneinfo…的軟鏈接), /etc/TZ, /etc/sysconfig/clock
-
環(huán)境變量:
TZ
, 使用舉例如下:bash中 export TZ="Europe/Moscow" date -u -s "2011-10-29 21:55:00" cshell中 setenv TZ Europe/Moscow
庫(kù)函數(shù)
這些為有關(guān)時(shí)間時(shí)區(qū)的常見系統(tǒng)庫(kù)函數(shù)望门。
-
time_t time(time_t *t)
返回
time_t
類型,值為UTC時(shí)間從0時(shí)0分0秒算起到現(xiàn)在所經(jīng)過(guò)的秒數(shù)锰霜。 -
struct tm*gmtime(const time_t*timep)
根據(jù)傳入的
time_t
返回類型為struct tm
結(jié)構(gòu)怒允,包含時(shí)、分锈遥、秒、日勘畔、周所灸、月、年炫七、日光節(jié)約時(shí)間標(biāo)記等信息的時(shí)間表示爬立,該時(shí)間為GMT時(shí)間,未經(jīng)時(shí)區(qū)轉(zhuǎn)換万哪。 -
struct tm *localtime(const time_t * timep)
根據(jù)傳入的
time_t
返回類型為struct tm
結(jié)構(gòu)侠驯,包含時(shí)、分奕巍、秒吟策、日、周的止、月檩坚、年、日光節(jié)約時(shí)間標(biāo)記等信息的時(shí)間表示诅福,該時(shí)間為當(dāng)?shù)貢r(shí)間匾委,已經(jīng)時(shí)區(qū)轉(zhuǎn)換。 -
time_t mktime(struct tm * timeptr)
將
struct tm
類型的時(shí)間轉(zhuǎn)換為time_t
類型氓润,值為UTC時(shí)間從0時(shí)0分0秒算起到現(xiàn)在所經(jīng)過(guò)的秒數(shù)赂乐。 -
char *ctime(const time_t *timep)
將傳入的
time_t
類型時(shí)間轉(zhuǎn)化為現(xiàn)實(shí)世界中的字符串表示形式,例如:Fri, 16 Oct 2015 23:12:18 +0800
-
char * asctime(const struct tm * timeptr)
將傳入的
struct tm
結(jié)構(gòu)類型時(shí)間轉(zhuǎn)化為現(xiàn)實(shí)世界中的字符串表示形式咖气,例如:Fri Oct 16 15:15:54 2015
-
int gettimeofday ( struct timeval * tv , struct timezone * tz )
返回當(dāng)前時(shí)間信息挨措,
struct timeval *tv
存放秒和微秒信息挖滤,struct timezone *tz
存放時(shí)區(qū)信息。 -
int settimeofday ( const struct timeval *tv,const struct timezone *tz)
根據(jù)傳入的時(shí)間信息
struct timeval *tv
, 和時(shí)區(qū)信息struct timezone *tz
設(shè)置當(dāng)前時(shí)間运嗜。
總之壶辜,time_t 是用秒數(shù)表示時(shí)間一般在系統(tǒng)時(shí)間戳中使用(一般就是UTC時(shí)間);struct tm 使用結(jié)構(gòu)體表示時(shí)間担租,在程序中使用(不同時(shí)區(qū)可能會(huì)有不同值)砸民;而現(xiàn)實(shí)中使用字符串來(lái)表示時(shí)間,字符串格式可以定制奋救。時(shí)區(qū)信息一般首先從環(huán)境變量中去讀岭参,如果沒(méi)有再?gòu)?/etc/TZ
等配置文件中去讀。
應(yīng)用舉例
在單一進(jìn)程中修改時(shí)區(qū)的方法
setenv("TZ","Europe/Moscow",1);
tzset();
時(shí)間同步校準(zhǔn)
假設(shè)安裝完系統(tǒng)發(fā)現(xiàn)時(shí)間與現(xiàn)實(shí)時(shí)間相差8小時(shí)尝艘。
一般是如下原因:安裝系統(tǒng)時(shí)選擇的時(shí)區(qū)是上海演侯,而系統(tǒng)啟動(dòng)后把bios時(shí)間認(rèn)為是utc時(shí)間,再根據(jù)上海所處時(shí)區(qū)背亥,將時(shí)間+8小時(shí)給我們秒际。這個(gè)時(shí)候的bios的時(shí)間和軟件的時(shí)間便出現(xiàn)不一致的情況。一個(gè)代表 utc 一個(gè)代表我們?cè)O(shè)置的cst(+8時(shí)區(qū))狡汉。
可做如下調(diào)整(例如系統(tǒng)為center os 6):
-
修改配置文件娄徊,將默認(rèn)環(huán)境變量更正為上海所在時(shí)區(qū),不使用UTC時(shí)間
$ vi /etc/sysconfig/clock ZONE="Asia/Shanghai" UTC=false ARC=false
這個(gè)文件影響系統(tǒng)啟動(dòng)后默認(rèn)的時(shí)間相關(guān)環(huán)境變量值盾戴,這里主要是
UTC=false
這個(gè)選項(xiàng)寄锐,設(shè)置硬件時(shí)鐘不是跟utc一致。 -
將linux的時(shí)區(qū)設(shè)置為 上海
$ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
加載配置時(shí)間環(huán)境變量的文件之前尖啡,需要指定好該文件的軟鏈接位置橄仆,通過(guò)這個(gè)可在各個(gè)時(shí)區(qū)配置文件下通用的
/etc/localtime
軟鏈接,可使系統(tǒng)能夠找到剛剛設(shè)置的時(shí)區(qū)配置文件衅斩,并設(shè)置好相應(yīng)的環(huán)境變量盆顾。 -
對(duì)準(zhǔn)時(shí)間ntp
$ntpdate 192.43.244.18
系統(tǒng)啟動(dòng)之后,系統(tǒng)時(shí)間通過(guò)
ntpdate
工具在網(wǎng)絡(luò)上獲取到矛渴。 -
設(shè)置硬件時(shí)間和軟件時(shí)間的一致并校準(zhǔn)
/sbin/hwclock -systohc
通過(guò)這個(gè)命令椎扬,將系統(tǒng)時(shí)間同步至硬件始終上,這樣我們的linux軟件和計(jì)算機(jī)硬件都是cst時(shí)間了--并且是我們?cè)O(shè)置的上海時(shí)區(qū)具温。
其它
實(shí)際問(wèn)題的分析案例
問(wèn)題描述
在設(shè)置好國(guó)家信息之后, 主頁(yè)上的時(shí)間信息并沒(méi)有根據(jù)時(shí)區(qū)進(jìn)行調(diào)整蚕涤。重啟之后,有時(shí)候會(huì)管用铣猩。
設(shè)置時(shí)間的位置其情況是:通過(guò) putenv()
設(shè)置好 TZ
環(huán)境變量揖铜,再通過(guò) tzset()
設(shè)置好時(shí)區(qū)信息。但是最后通過(guò) time()
和 localtime()
函數(shù)得到的時(shí)間信息只在進(jìn)程1中起作用达皿。
需要確認(rèn)的問(wèn)題
- 環(huán)境變量的獲取與設(shè)置
- 時(shí)間/時(shí)區(qū)/時(shí)鐘的概念
- 有關(guān)時(shí)區(qū)的環(huán)境變量/配置文件/調(diào)用接口
分析原因
代碼還沒(méi)有深入看過(guò)天吓,根據(jù)前面的原理分析有如下可能的原因:
有兩個(gè)進(jìn)程贿肩, 設(shè)置時(shí)間的進(jìn)程, 和顯示時(shí)間的進(jìn)程龄寞。
在設(shè)置時(shí)間的進(jìn)程中設(shè)置時(shí)區(qū)環(huán)境變量
TZ
汰规,時(shí)區(qū)信息在設(shè)置時(shí)間的進(jìn)程中起作用;但是設(shè)置好時(shí)區(qū)信息后物邑,顯示時(shí)間的進(jìn)程仍然根據(jù)原來(lái)的環(huán)境變量TZ
顯示時(shí)間溜哮,所以顯示的時(shí)間和設(shè)置的時(shí)區(qū)不一致。需要確認(rèn)的是:確認(rèn)設(shè)置時(shí)間的進(jìn)程設(shè)置后環(huán)境變量后色解,設(shè)置的值是否已正確保存到合適的位置茂嗓;顯示時(shí)間的進(jìn)程是否會(huì)及時(shí)更新環(huán)境變量并顯示,并且是否是基于設(shè)置時(shí)間進(jìn)程保存的配置文件中讀取信息科阎、更新環(huán)境變量再進(jìn)行顯示述吸。
參考
man 3 tzset
解決嵌入式Linux中的時(shí)區(qū)問(wèn)題
linux調(diào)整系統(tǒng)時(shí)間和時(shí)區(qū)的方法
Linux下設(shè)置時(shí)區(qū)(通過(guò)shell設(shè)置和程序中設(shè)置)及程序中設(shè)置環(huán)境變量
linux時(shí)區(qū)時(shí)間問(wèn)題ntp