1. 程式人生 > 實用技巧 >shell 指令碼中日期運算

shell 指令碼中日期運算

平常寫shell指令碼的過程中,經常要用到日期的運算,比如:日期的加減、與UTC時間換算,比較大小等等,下面就來聊一聊這些常用的日期運算

日期加減

  • 秒增減
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "70 second 2020-10-20 12:00:00"
2020-10-20 12:01:10
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "-70 second 2020-10-20 12:00:00"
2020-10-20 11:58:50
  • 分鐘增減
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "10 minute 2020-10-20 12:00:00"
2020-10-20 12:10:00
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "-10 minute 2020-10-20 12:00:00"
2020-10-20 11:50:00
  • 小時增減
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "1 hour 2020-10-20 12:00:00"
2020-10-20 13:00:00
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "-1 hour 2020-10-20 12:00:00"
2020-10-20 11:00:00
  • 天增減
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "3 day 2020-10-20 12:00:00"
2020-10-23 12:00:00
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "-3 day 2020-10-20 12:00:00"
2020-10-17 12:00:00
  • 周增減
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "1 week 2020-10-20 12:00:00"
2020-10-27 12:00:00
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "-1 week 2020-10-20 12:00:00"
2020-10-13 12:00:00
  • 月增減
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "2 month 2020-10-20 12:00:00"
2020-12-20 12:00:00
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "-2 month 2020-10-20 12:00:00"
2020-08-20 12:00:00
  • 年增減
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "1 year 2020-10-20 12:00:00"
2021-10-20 12:00:00
[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "-1 year 2020-10-20 12:00:00"
2019-10-20 12:00:00
  • 年月日時分秒增減

年月日時分秒除了每一個單獨進行日期增減之外,還可以一起使用

[root@ecs-centos-7 ~]# date +'%Y-%m-%d %H:%M:%S' -d "1 year 2 month 1 week 3 hour -10 minute 40 second 2020-10-20 12:00:00"
2021-12-27 14:50:40

  • 一個月中第幾天
[root@ecs-centos-7 ~]# date +%Y%m%d
20201023
[root@ecs-centos-7 ~]# date +%d
23
[root@ecs-centos-7 ~]# date +%d -d "20201013"
13

date +%d 命令是計算當前日期( 2020年10月23日 ) 是一個月中的第幾天

date +%d -d "20201013" 命令是計算 2020年10月13日 是一個月中第幾天

  • 一年中第幾周
[root@ecs-centos-7 ~]# date +%Y%m%d
20201023
[root@ecs-centos-7 ~]# date +%V
43
[root@ecs-centos-7 ~]# date +%V -d "20201005"
41

上面例子中, date +%V 命令是計算當前日期是一年中第幾周,星期一是一週的第一天,取值範圍是 01-53,date +%V -d "20201005" 命令是計算指定日期 ( 20201005 ) 是一年中第幾周

  • 一週中第幾天
[root@ecs-centos-7 ~]# date +%Y%m%d
20201023
[root@ecs-centos-7 ~]# date +%u
5
[root@ecs-centos-7 ~]# date +%u -d "20201004"
7

上面的例子中,date +%u 命令是計算當前日期是一週中第幾天,取值範圍是 1 - 7,分別表示週一至週日,結果是 5,表示當前這一天是週五, date +%u -d "20201004" 命令是計算指定日期 ( 20201004 ) 是一週中第幾天,結果是 7 ,表示 2020年10月4日是週日

[root@ecs-centos-7 ~]# date +%Y%m%d
20201023
[root@ecs-centos-7 ~]# date +%w
5
[root@ecs-centos-7 ~]# date +%w -d "20201004"
0

上面例子中,date +%w 命令是也是計算當前日期是一週中第幾天,取值範圍是 0 - 6 , 0 代表週日,1 - 6 分別代表週一至週六

命令 date +%w -d "20201004" 是計算指定日期 ( 20201004 ) 是一週中第幾天,結果是 0,表示2020年10月4日是週日

月第一天和月最後一天

[root@ecs-centos-7 ~]# date +"%Y-%m-%d"  -d  "-$(($(date +%d -d '2020-10-20') -1 )) days  2020-10-20"
2020-10-01

[root@ecs-centos-7 ~]# date +"%Y-%m-%d"  -d  "-$(($(date +%d -d '2020-10-20') )) days +1 month  2020-10-20"
2020-10-31

上面例子中,date +"%Y-%m-%d" -d "-$(($(date +%d -d '2020-10-20') -1 )) days 2020-10-20" 命令是計算日期 2020-10-20 中月份的第一天, 結果是 2020-10-01

命令 date +"%Y-%m-%d" -d "-$(($(date +%d -d '2020-10-20') )) days +1 month 2020-10-20" 是計算日期 2020-10-20 中月份的最後一天, 結果是 2020-10-31

日期和UTC時間互相轉換

  • 日期轉 UTC 時間

UTC時間是整數,把日期轉成UTC時間,更方便各種計算

[root@ecs-centos-7 ~]# date +%s
1603443806
[root@ecs-centos-7 ~]# date +%s -d "2020-10-20 12:00:00"
1603166400
[root@ecs-centos-7 ~]# date +%s -d "2020-10-20 00:00:00"
1603123200
[root@ecs-centos-7 ~]# date +%s -d "2020-10-20"
1603123200
[root@ecs-centos-7 ~]# date +%s -d "2020-10-01"
1601481600

上面例子中,date +%s 命令是把當前時間轉成 UTC 時間,date +%s -d "2020-10-20 12:00:00" 命令是把 2020-10-20 12:00:00 轉成UTC時間

  • UTC時間轉日期
[root@ecs-centos-7 ~]# date +%s -d "2020-10-20 12:00:00"
1603166400
[root@ecs-centos-7 ~]# date -d "@1603166400"
2020年 10月 20日 星期二 12:00:00 CST

命令 date +%s -d "2020-10-20 12:00:00" 是計算 2020-10-20 12:00:00 的UTC時間,這裡主要是為了和後面UTC時間轉日期做對比用的

命令 date -d "@1603166400" 是計算UTC時間( 1603166400 ) 對應的日期,計算結果是 2020年 10月 20日 星期二 12:00:00 CST 前一條命令的日期引數是一致的

日期比較大小

shell中直接比較日期相當於字串比較,可以先把日期轉成UTC時間再進行比較,下面是一個日期比較的測試指令碼 ( t.sh ),執行時需要傳入兩個待比較的日期

#!/bin/bash

date1=$(date +%s -d "$1")
date2=$(date +%s -d "$2")

if [[ ${date1} -lt ${date2} ]]; then
	echo " $1  <  $2 "
elif [[ ${date1} -eq ${date2} ]]; then
	echo " $1  =  $2 "
else
	echo " $1  >  $2 "
fi

執行測試指令碼,具體結果如下:

[root@localhost shell_test]# ./t.sh "20201020" "20201020"
 20201020  =  20201020 
[root@localhost shell_test]# ./t.sh "20201020" "20201021"
 20201020  <  20201021 
[root@localhost shell_test]# ./t.sh "20201020" "20201019"
 20201020  >  20201019 
 [root@localhost shell_test]# 
 
[root@localhost shell_test]# ./t.sh "2020-10-20 00:00:01" "2020-10-20 00:00:00"
 2020-10-20 00:00:01  >  2020-10-20 00:00:00 
[root@localhost shell_test]# ./t.sh "2020-10-20 00:00:01" "2020-10-20 00:00:01"
 2020-10-20 00:00:01  =  2020-10-20 00:00:01 
[root@localhost shell_test]# ./t.sh "2020-10-20 00:00:01" "2020-10-20 00:00:10"
 2020-10-20 00:00:01  <  2020-10-20 00:00:10 
[root@localhost shell_test]# 

從結果可以看出, t.sh 指令碼傳入日期引數既可以只有年月日又可以年月日時分秒都有,而且日期的格式既可以是 20201020 格式,又可以是 2020-10-20 00:00:00 格式的

日期迴圈遍歷

在工作中,經常要處理一段時間內的日誌,需要遍歷日期,然後對每天的日誌做處理,下面的測試指令碼 ( t.sh ) 是測試日期遍歷的, 指令碼內容如下:

#!/bin/bash


#開始日期
begindate=$1
#結束日期
enddate=$2

#後一天日期,用於迴圈
nextdate=${begindate}
#後一天日期的utc時間,用於比較日期
nextutc=$(date +%s -d "${nextdate}")
#結束日期的UTC時間
endutc=$(date +%s -d "${enddate}")


while [ ${nextutc} -le ${endutc} ]
do
	echo "process ${nextdate} log..."
	#計算後一天的日期
	nextdate=$(date -d "${nextdate} 1 day" +%Y%m%d)
	#計算後一天日期的utc時間
	nextutc=$(date +%s -d "${nextdate}")
	
done

執行測試指令碼,具體結果如下:

[root@localhost shell_test]# ./t.sh "20201020" "20201023"
process 20201020 log...
process 20201021 log...
process 20201022 log...
process 20201023 log...