Ksh 對日期的處理

項目中需要使用shell編程對日期進行處理,shell使用的是ksh,系統爲AIX。

需求是:輸入一個yyyymmdd日期格式的日期,獲得這個日期的前N天的日期或者後N天的日期。

main查詢下來ksh裏面的date命令沒有-d這個參數,所以我自己寫了該shell:

#!/bin/ksh

# get date 截取日期
# input yyyymmdd
# output $year $month $day $yearNum $monthNum $dayNum
getDate(){
	# the input length is 8
	if [ `expr length $1` -ne 8 ]; then
		exit -1;
	fi
	# All the input values are numbers
	if [ ! -z "$(echo $1 | sed 's#[0-9]##g')" ]; then
		exit -1;
	fi
	
	# get year
	year=`echo $1 | cut -c 1-4`
	
	# get month
	month=`echo $1 | cut -c 5-6`
	
	# get day
	day=`echo $1 | cut -c 7-8`

}

# get YearFlg 驗證是否爲閏年
# input yyyy
# output $yearFlg
getYearFlg(){
	local year=`expr $1 + 0`
	if [ $? -ne 0 ]; then
		exit -1
	fi
	
	if [[ `expr $year % 4` -eq 0 && `expr $year % 100` -ne 0 ]]; then
			yearFlg=1;
			elif [ `expr $year % 400` -eq 0 ]; then
				yearFlg=1;
			else
				yearFlg=0;
	fi
}

# get MaxDay 獲得每個月的最大天數
# input yyyy mm
# output $maxDay
getMaxDay(){

	local month=`expr $2 + 0`
	if [ $? -ne 0 ]; then
		exit -1
	fi
	
	getYearFlg $1
	
	case $month in
		1|3|5|7|8|10|12) maxDay=31;;
		4|6|9|11) maxDay=30;;
		2)
			if [ $yearFlg -eq 1 ]; then
				maxDay=29
			else 
				maxDay=28
			fi
			;;
	esac
}
# check date 檢查日期是否爲yyyymmdd格式
# input yyyymmdd
checkDate(){
	getDate $1
	if [ $? -ne 0 ]; then
		exit -1
	fi
	
	# check year
	if [[ `expr $year + 0` -lt 0 || `expr $year + 0` -gt 9999 ]]; then
		exit -1
	fi
	
	# check month
	if [[ `expr $month + 0` -lt 1 || `expr $month + 0` -gt 12 ]]; then
		exit -1
	fi
	
	getMaxDay $year $month
	# check day
	if [[ `expr $day + 0` -lt 1 || `expr $day + 0` -gt $maxDay ]]; then
		exit -1
	fi
}

# formmat yyyymmdd
# input yyyy($1) mm($2) dd($2)
# output $yyyymmdd
formtYYYYMMDD(){
	local yearlen=`expr length $1`
	if [ $yearlen -lt 4 ]; then
		case $yearlen in
			1) year=000$1;;
			2) year=00$1;;
			3) year=0$1;;
		esac
	fi
	local monthlen=`expr length $2`
	if [ $monthlen -lt 2 ]; then
		month=0$2
	fi
	
	local daylen=`expr length $3`
	if [ $daylen -lt 2 ]; then
		day=0$3
	fi
	yyyymmdd=$year$month$day
}


#
# input yyyymmdd($1) num($2)
# output yyyymmdd
dateBefore(){
	getDate $1
	if [ $? -ne 0 ]; then
		exit -1
	fi
	num=$2
	# 4year =1461day
	if [ $num -gt 1461 ]; then
		num=`expr $2 % 1461`
		year=`expr $year - $2 / 1461 \* 4`
	fi
	
	dayNum=`expr $day + 0`
	if [ $dayNum -gt $num ]; then
		day=`expr $dayNum - $num`
		
		formtYYYYMMDD $year $month $day
		echo $yyyymmdd
		
		else
			month=`expr $month - 1`
			if [ $month -eq 0 ]; then
				month=12
				year=`expr $year - 1`
			fi
			getMaxDay $year $month
			dayNum=`expr $dayNum + $maxDay`
			if [ $dayNum -gt $num ]; then
				day=`expr $dayNum - $num`
				num=0
			else
				num=`expr $num - $maxDay`
			fi
			formtYYYYMMDD $year $month $day
			dateBefore $yyyymmdd $num
	fi
}

#
# input yyyymmdd($1) num($2)
# output yyyymmdd
dateAfter(){
	
	getDate $1
	if [ $? -ne 0 ]; then
		exit -1
	fi
	num=$2
	# 4year =1461day
	if [ $num -gt 1461 ]; then
		num=`expr $2 % 1461`
		year=`expr $year + $2 / 1461 \* 4`
	fi
	getMaxDay $year $month
	dayNum=`expr $day + $num`
	if [ $dayNum -lt $maxDay ]; then
		day=`expr $day + $num`
		formtYYYYMMDD $year $month $day
		echo $yyyymmdd
		else
			if [ $num -ge $maxDay ]; then
				num=`expr $num - $maxDay`
				else
				day=`expr $num + $day - $maxDay`
				num=0
			fi
			
			month=`expr $month + 1`
			if [ $month -eq 13 ]; then
				month=1
				year=`expr $year + 1`
			fi
			formtYYYYMMDD $year $month $day
		dateAfter $yyyymmdd $num
	fi
	
}



# input yyyymmdd($1) num($2)
# example dateType 20180321 -32
# example dateType 20180321 +32
# output yyyymmdd
dateType(){
	# input not null
	if [ $# -ne 2 ]; then
		exit -1
	fi
	
	# check input yyyymmdd
	checkDate $1
	if [ $? -ne 0 ]; then
		exit -1
	fi
	
	# check days
	if [ -z "$(echo $2 | sed 's#^[+|-][1-9][0-9]*##g')" ]; then
		flg=`echo $2 | cut -c 1`
		Num=`echo $2 | cut -c 2-`
		# recursion
		if [ "$flg" = "-" ]; then
			dateBefore $1 $Num
			elif [ "$flg" = "+" ];then
				dateAfter $1 $Num
			else
				exit -1
		fi
	fi

}


echo "###############################"
dateType 20180321 -41 # output 20180208
dateType 20180208 +41 # output 20180321
echo "###############################"

程序主要的知識點包括遞歸的運用、正則表達式的運用、shell函數的調用,awk與sed命令的運用等。。。。

本程序截取了與日期相關的處理,還有些地方需要完善:如只可以處理公元后的日期、處理日期也只是yyyymmdd格式的日期,

遞歸並沒有採用尾遞歸,性能也有待提升。

注意點:

shell裏面的變量如果沒有使用local聲明,一般都是全局變量;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章