對日期進行操作,相信每一個 RD 都不會陌生,在我所主要接觸、工作的 3 種語言裡,感覺 shell 下的 date 設計的最簡潔實用,其次是 python,最複雜難用的當屬 java 中的 date 了。
下面要介紹的 date 是指 linux 下的 GNU date, unix 使用者或者非 gnu date 使用者隻能 YY 下了,因為下文的絕大多數特性你那都不支援的。
1、擷取目前時間 并格式化
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
june@Win7 192.168.1.101 01:49:52 ~ >
2、日期的二 則運算
GNU date 的日期加減運算是支援自然語言的,主要有三種指令:
- 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 ~ >
3、字元串轉換為日期、指定時間格式
#美國式時間格式
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 -d @103 +%m"min"%S"s"
#日期轉時間戳
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"
4、注 意時區問題
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
5、最後的技能: (1)當 %H%M 遇上 ` `
請看下面這段代碼,很多人估計會犯的錯誤:
[[ `date +'%H%M'` -eq 0 ]]
恭喜你,你每天早上的 8、9 點執行腳本的話都會遇到:
value too great for base (error token is "0950") 這樣的錯誤,
這是因為 [[]] 把 0950 當成 8 進制來解析了,是以抛異常了。
解決辦法有如下 3 種,可以選擇你認為最爽的一種修複:
- (1.1)換成 [ 0 -eq 0950 ] && echo 1 即可
- (1.2)或者手動指定進制也行 [[ 950 -eq 10#0950 ]] && echo 1
- (1.3)讓 '%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 ~ >
(2)如何快速擷取一個日期清單
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 ~ >
好吧,今天的主題就到此為止了,希望本文能對你有所幫助。
簡單、高效一直是每個 Linuxer 追求的目标,如果你也有這方面的技巧/問題需要交流,歡迎通過下面的評論來與我保持聯系。
6、Ref
(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