最近很久沒 update 了,一來是近期有點煩人的私事須要處理,二來是工做有點忙,業餘時間還要整個 PPT,蒐集素材啥的,很是耗時間。。。好吧,這都是藉口,實際上是人變懶了。。。⊙﹏⊙ 不過我發現最近 1 個月以來,我關注的一些 Blog,一半以上也都沒更新了,看來對你們來講年末都是多事之秋呀~html
好了,言歸正傳,以前有介紹過《linux 系統監控、診斷工具之 top 詳解》、《linux 系統監控、診斷工具之 lsof 用法簡介》,今天再來介紹一個使用頻率很高的 linux 命令:datejava
對日期進行操做,相信每個 RD 都不會陌生,在我所主要接觸、工做的 3 種語言裏,感受 shell 下的 date 設計的最簡潔實用,其次是 python,最複雜難用的當屬 java 中的 date 了。python
下面要介紹的 date 是指 linux 下的 GNU date, unix 用戶或者非 gnu date 用戶只能 YY 下了,由於下文的絕大多數特性你那都不支持的。linux
june@Win7 192.168.1.101 01:46:27 ~ > date Sat, Dec 21, 2013 1:49:15 AM june@Win7 192.168.1.101 01:49:15 ~ > date -I 2013-12-21 june@Win7 192.168.1.101 02:16:52 ~ > date -d tomorrow +%Y-%m-%d 2013-12-22 june@Win7 192.168.1.101 02:17:49 ~ > date -d yesterday +%Y-%m-%d 2013-12-20 june@Win7 192.168.1.101 02:18:05 ~ > date -d last-day +%Y-%m-%d 2013-12-20 june@Win7 192.168.1.101 02:18:15 ~ > date +'%F %T' 2013-12-21 01:49:26 june@Win7 192.168.1.101 01:49:26 ~ > date +"%Y-%m-%d %H:%M:%S" 2013-12-21 01:49:52 Jun@VAIO 192.168.31.171 23:43:29 ~ > date +%:z # 獲取時區與UTC的差 +08:00 Jun@VAIO 192.168.31.171 23:44:15 ~ >
GNU date 的日期加減運算是支持天然語言的,主要有三種指令:shell
last/next指令安全
ago指令函數
負數指令工具
june@Win7 192.168.1.101 02:10:00 ~ > date -I && date -I -d'last sunday -7 days' 2013-12-21 2013-12-08 june@Win7 192.168.1.101 02:10:03 ~ > # 注意:語法對年月日、時分秒都適用 june@Win7 192.168.1.101 01:59:47 ~ > date -d '20110614 next-day' +%Y-%m-%d 2011-06-15 june@Win7 192.168.1.101 02:01:17 ~ > date -d '20110614 1 days' +%Y-%m-%d 2011-06-15 june@Win7 192.168.1.101 02:01:39 ~ > date -d '20110614 1 days ago' +%Y-%m-%d 2011-06-13 # 注意最好用天然語言,別用 +1 -1 操做,某些早期版本(如RedHat 4U7)不支持可能形成錯誤結果,並且這種寫法會和時區語法衝突,容易出問題。 june@Win7 192.168.1.101 02:01:44 ~ > date -d '20110614 -1 days' +%Y-%m-%d 2011-06-13 june@Win7 192.168.1.101 02:01:57 ~ > date -d '20110614 +1 days' +%Y-%m-%d 2011-06-15 june@Win7 192.168.1.101 02:02:01 ~ >
注意:spa
date 天然語言指令在天、小時、分鐘多單位混合的時候注意每一個單位都要加限定條件 ago/-,不然默認是 after:.net
Jun@VAIO 192.168.1.216 15:48:36 ~ > date -d'-1 hours -30 minutes' 2015年08月 9日 14:18:54 Jun@VAIO 192.168.1.216 15:48:54 ~ > date -d'1 hours ago 30 mins ago' 2015年08月 9日 14:18:59 Jun@VAIO 192.168.1.216 15:49:00 ~ > date -d'1 hours 30 mins ago' 2015年08月 9日 16:19:06 Jun@VAIO 192.168.1.216 15:49:06 ~ >
#美國式時間格式 june@Win7 10.59.9.38 18:02:30 ~ > date -d'31/Oct/2013:00:00:10 +0800' +'%F %T' date: invalid date `31/Oct/2013:00:00:10 +0800' june@Win7 10.59.9.38 18:02:34 ~ > date -d'31 Oct 2013 00:00:10 +0800' +'%F %T' 2013-10-31 00:00:10 june@Win7 10.59.9.38 18:07:34 ~ > #秒轉爲分 date -u -d@3613 +%H"h"%M"min"%S"s" 01h00min13s #日期轉時間戳 june@Win7 192.168.1.101 02:02:01 ~ > date -d "2010-12-11" +%s 1291996800 #時間戳轉日期 june@Win7 192.168.1.101 02:04:22 ~ > date -d@1291996800 -I 2010-12-11 # 下面的是很是規方法,拓展思路而已 june@Win7 192.168.1.101 02:10:03 ~ > echo 1307980800 | awk '{T=strftime("%F %T",$1);print T}' 2011-06-14 00:00:00 june@Win7 192.168.1.101 02:16:15 ~ > echo '1307980800' |sed -r -e "s/(.*)/date -d @\1 '+%Y-%m-%d %H:%M:%S'/e" 2011-06-14 00:00:00 june@Win7 192.168.1.101 02:16:52 ~ > #此方法在大於2038年的時候會有問題,即便是 64bit 也是有問題的。32473710849 date -d "UTC 1970-01-01 1234567890 secs"
date 裏面時間的 + - 注意格式會影響結果/時區(最安全的寫法是不要帶符號,用天然語言便可):
date -d'2013-07-01 09:52:33 +1 minutes' # 這個+1被當成時區了 Mon, Jul 01, 2013 4:53:33 PM date -d'2013-07-01 09:52:33 1 minutes' # 一樣 -1 也會有問題 Mon, Jul 01, 2013 9:53:33 AM date -u --date='+2 minutes 13-07-01 09:52:33' # 把 + - 時間放在最前面也行 Mon Jul 1 09:54:33 UTC 2013 date -u --date='13-07-01 09:52:33 +0 +2 minutes' # 注意前面的 -u UTC時間,少了也會有問題 Mon Jul 1 09:54:33 UTC 2013 date -u --date='13-07-01 09:52:33 GMT +2 minutes' # 指定時區 Mon Jul 1 09:54:33 UTC 2013
請看下面這段代碼,不少人估計會犯的錯誤:
[[ `date +'%H%M'` -eq 0 ]]
恭喜你,你天天早上的 八、9 點執行腳本的話都會遇到:
value too great for base (error token is "0950") 這樣的錯誤,
這是由於 [[]] 把 0950 當成 8 進制來解析了,因此拋異常了。
這裏的規則是:
以 0 開頭默認 8 進制,以 0x 開頭 16 進制,或者你用 n# 的方式手動指定:
[[ 0010 -eq 8 ]] && echo 111 111 [[ 8#10 -eq 8 ]] && echo 111 111 [[ 0x10 -eq 16 ]] && echo 111 111
解決辦法有以下 4 種,能夠選擇你認爲最爽的一種修復:
(1.1)換成 [ 0 -eq 0950 ] && echo 1 便可
(1.2)或者手動指定進制也行 [[ 10#`date +%H%M` -eq 10#0950 ]] && echo 1
(1.3)兩邊當作字符串來對待 [[ "`date +'%H%M'`" == "0950" ]] && echo 1
(1.4)加 - 格式化佔位符,讓 '%H%M' 這種格式不帶前導符 0:
june@Win7 192.168.1.101 02:30:03 ~ > date +'[%H%M]' [0230] june@Win7 192.168.1.101 02:30:19 ~ > date +'[%_H%_M]' [ 230] june@Win7 192.168.1.101 02:30:26 ~ > date +'[%-H%-M]' [230] june@Win7 192.168.1.101 02:30:35 ~ >
june@Win7 192.168.1.101 02:30:35 ~ ># seq -w,seq -f%.8g, echo {..} date -f <(seq -f%.0f 20130227 20130301) +%Y%m%d 2>/dev/null 20130227 20130228 20130301 june@Win7 192.168.1.101 02:33:50 ~ >
判斷今天是否是月末: [ `date --date='next day' +'%B'` != `date +'%B'` ] && echo 'end of month' || echo 'not end of month' [[ `date +%d` -eq `echo $(cal)|grep -Po '\d+$'` ]] && echo 月末 || echo 非月末 獲得當月/上月的第1天/最後一天: # First Day, current month: ## %d = day of month. date -d "-0 month -$(($(date +%d)-1)) days" # First Day, last month: date -d "-1 month -$(($(date +%d)-1)) days" # Last Day, last month: date -d "-$(date +%d) days -0 month" # Last Day, current month: date -d "-$(date +%d) days +1 month" # Last Day, month before last month: date -d "-$(date +%d) days -1 month" 獲得指定日期當月的最後一天: Jun@VAIO 192.168.1.216 23:57:02 ~ > getlastDay_func1(){ echo `echo $(cal $(echo $1|awk -vFIELDWIDTHS="4 2 2" '{print $2,$1}'))|grep -Po '\d+$'`; } Jun@VAIO 192.168.1.216 23:57:45 ~ > getlastDay_func1 20150214 28 Jun@VAIO 192.168.1.216 23:56:44 ~ > getlastDay_func2(){ echo `date -d"-1 days +1 month $(echo $1|sed -r 's/(....)(..).*/\1-\2-01/')" +%Y%m%d`; } Jun@VAIO 192.168.1.216 23:56:52 ~ > getlastDay_func2 20150214 20150228 Jun@VAIO 192.168.1.216 23:57:02 ~ >
好吧,今天的主題就到此爲止了,但願本文能對你有所幫助。
簡單、高效一直是每一個 Linuxer 追求的目標,若是你也有這方面的技巧/問題須要交流,歡迎經過下面的評論來與我保持聯繫。
(1)一個關於date -d '1 month ago' 的 「bug」
http://hi.baidu.com/leejun_2005/item/8cb255757225835b0d0a078a
(2)date很是規用法總結
http://scmbob.org/special_usage_of_date.html
(3)shell 轉換時間戳獲取兩個時間段的全部日期,返回list
http://hi.baidu.com/leejun_2005/item/92854594db7ca831326eeb69
(4)python datetime 時間日期處理小結
http://hi.baidu.com/leejun_2005/item/abaf4d0e3aac8a153b53ee69
(5)自定義 java 日期、時間 處理函數集