我正在尝试编写一个shell脚本,用于确定用户输入年份当前日期与复活节之间的年,月和日之间的差异。例如,用户输入1995并且脚本应该计算自那时以来经过了多少年并将这些天转换为年,月和日并显示结果。 我正在粘贴我的所有代码
#!/bin/bash
echo "This script will show you on which day is Easter for the chosen year of the Gregorian calendar!"
x=0
read x
A=$((x % 19))
B=$((x / 100))
C=$((x % 100))
D=$((B / 4))
E=$((B % 4))
G=$(((8 * B + 13) / (25)))
H=$(((19 * A + B - D - G + 15) % (30)))
M=$(((A + 11 * H) / (319)))
J=$((C / 4))
K=$((C % 4))
L=$(((2 * E + 2 * J - K - H + M + 32) % (7)))
N=$(((H - M + L + 90) / (25)))
P=$(((H - M + L + N + 19) % (32)))
Z=$(date --date="$x-$N-$P" +%A)
echo
echo "Easter is `date --date="$x-$N-$P"`"
([ "`cal 2 $x | grep 29`" != "" ] && echo -e "\n$x is a leap year\n")
([ "`cal 2 $x | grep 29`" = "" ] && echo -e "\n$x is not a leap year\n")
yearnow=$(date +%Y)
year=$(($x - $yearnow))
year1=$(($yearnow - $x))
if (($x > $yearnow))
then
echo "There are $year years until Easter in $x."
else
echo "$year1 years have passed since Easter in $x."
fi
pmonths=0
if (($x > $yearnow))
then
pmonths=$(($year * 12))
echo "There are $pmonths months until Easter."
else
pmonths=$(($year1 * 12))
echo "$pmonths months have passed since Easter in $x."
fi
#checking and counting how many leap and normal years are there between the present year and the chosen one
counter=1
leapycounter=0
nycounter=0
if (($x > $yearnow))
then
while (($counter < $year))
do
leapy=$(($x + $counter))
if (($leapy == (($leapy / 4) - ($leapy / 100) + ($leapy / 400))))
then leapycounter=$(($leapycounter + 1))
else nycounter=$(($nycounter + 1))
fi
counter=$(($counter + 1))
done
fi
#checking if the present year is leap so the days left from this year can be calculated
if (($x > $yearnow))
then
datenow=$(date +%j)
datenow=`echo $datenow|sed 's/^0*//'`
if (($yearnow == (($yearnow / 4) - ($yearnow / 100) + ($yearnow / 400))))
then
datenow=$((366 - $datenow))
else
datenow=$((365 - $datenow))
fi
datethen=$(date --date="$x-$N-$P" +%j)
datethen=`echo $datethen|sed 's/^0*//'`
days=$(($datethen + $datenow))
lyc=$((($leapycounter * 366) + ($nycounter * 365)))
dayspassed=$(($lyc + $days))
echo "There are $dayspassed days until Easter."
else
datethen=$(date --date="$x-$N-$P" +%j)
datethen=`echo $datethen|sed 's/^0*//'`
if (($yearnow == (($yearnow / 4) - ($yearnow / 100) + ($yearnow / 400))))
then
datethen=$((366 - $datethen))
else
datethen=$((365 - $datethen))
fi
datenow=$(date +%j)
datenow=`echo $datenow|sed 's/^0*//'`
days=$(($datethen + $datenow))
lyc=$((($leapycounter * 366) + ($nycounter * 365)))
dayspassed=$(($lyc + $days))
echo "$dayspassed days have passed since Easter in $x."
fi
#this should be converting the days into years, months and days
dtomconst=$(((((365/12)*3)+(366/12))/4))
months=$(($dayspassed / $dtomconst))
monthsleft=$(($months % 12))
years=$(($months / 12))
daysleft=$((($dayspassed - ($monthsleft * $dtomconst)) - (365*$years)))
echo "months are $months"
echo "daysleft are $daysleft"
echo $years
months=$(($months + $monthsleft))
echo $monthsleft
echo "months after calculations: $months"
所以问题是它不能正确计算日期,特别是过去几年。此外,如果用户输入像1888这样的年份,脚本会显示错误,我不知道为什么。 如果有人可以就我的问题说一两句话,我会非常感激。提前谢谢。
答案 0 :(得分:1)
正如评论中所指出的,脚本的挑战将是确定某一年复活节发生的日期,因为每年的日期不同,每年的日期不同。进一步使差异计算复杂化的是月份的概念,因为闰年会改变2月的长度。还有偶尔会leap-second
投入使用。
但是,如评论中所示,一旦您到达复活节某一年,您可以让date
功能为您完成剩余的大部分工作。给定任何日期,您可以将该值传递给date
函数,并将该值转换为自纪元以来的秒数。请注意,这在1970
之前的数年内并没有直接帮助,但您可以进一步延伸,以近似的方式操纵每年的秒数。
一旦你有复活节,获得当前时间,以纪元为单位的秒数表示,date
是微不足道的。然后,您可以使用不同的工具,转换表示所选复活节时间的秒数,然后可以用years, days, hours, minutes, seconds
表示。当然,这些必须加以考虑leap
效果,具体取决于所需的准确程度。
以下是解决时差问题的简单示例。包含的函数,以秒为单位给出时间差异,然后声明(根据需要)作为参数给出的时间所代表的年,日,小时,分钟和秒。这并不能解决您的所有问题,但希望它能够帮助您以更轻松的方式处理该信息。如果您对内容有任何疑问,请与我们联系:
#!/bin/bash
## time difference function takes an argument in seconds, and then calculates,
# declares and fills variables 'years' 'days' 'hours' 'minutes' and 'seconds'
# representing the time in seconds given as the argument. The values are only
# declared as necessary allowing a test for their presence.
function sec2ydhms {
[ -n $1 ] || { printf "%s() error: insufficient arguments\n" "$FUNCNAME"; return 1; }
local secperday=$((24 * 3600))
local secperyr=$((365 * secperday))
local remain=$1
# printf "\nremain: %s\n\n" "$remain"
if [ "$remain" -ge "$secperyr" ]; then
declare -g years=$((remain/secperyr))
remain=$((remain - (years * secperyr)))
fi
if [ "$remain" -ge "$secperday" ]; then
declare -g days=$((remain/secperday))
remain=$((remain - (days * secperday)))
fi
if [ "$remain" -ge 3600 ]; then
declare -g hours=$((remain/3600))
remain=$((remain - (hours * 3600)))
fi
if [ "$remain" -ge 60 ]; then
declare -g minutes=$((remain/60))
fi
declare -g seconds=$((remain - (minutes * 60)))
}
oifs=$IFS # save old IFS, and set to only break on newline
IFS=$'\n' # allowing date formats containing whitespace
printf "\n Enter the date for Easter (in past): "
read edate # read date entered
eepoch=$(date -d "$edate" +%s) # convert Easter date to seconds since epoch
now=$(date +%s) # get current time since epoch
sec2ydhms $((now-eepoch)) # compute time from Easter in Y,D,H,M,S
## print time since Easter
printf "\n Time since %s:\n\n" "$(date -d @"${eepoch}")"
[ -n "$years" ] && printf " %4s years\n" "$years"
[ -n "$days" ] && printf " %4s days\n" "$days"
[ -n "$hours" ] && printf " %4s hours\n" "$hours"
[ -n "$minutes" ] && printf " %4s minutes\n" "$minutes"
[ -n "$seconds" ] && printf " %4s seconds\n\n" "$seconds"
exit 0
<强>输出:强>
$ bash easter.sh
Enter the date for Easter (in past): 03/21/1985
Time since Thu Mar 21 00:00:00 CST 1985:
29 years
254 days
21 hours
12 minutes
16 seconds