计算天数并将其显示为年、月、两个日期之间的天数shell脚本

计算天数并将其显示为年、月、两个日期之间的天数shell脚本,shell,date-arithmetic,Shell,Date Arithmetic,我正在尝试编写一个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)

我正在尝试编写一个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"
#/bin/bash
echo“此脚本将向您显示所选公历年的哪一天是复活节!”
x=0
读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=“$x-$N-$P”+%A)
回声
echo“复活节是`date--date=“$x-$N-$P”`”
([“`cal2$x | grep29`”!=”]&&echo-e“\n$x是闰年\n”)
([“`cal2$x | grep 29`=”]&&echo-e“\n$x不是闰年\n”)
向往=$(日期+%Y)
年份=$($x-$W))
第1年=$($EARSHOW-$x))
如果($x>$W))
然后
echo“在$x中,复活节还有$year年。”
其他的
echo“$year1年从$x复活节以来已经过去了。”
fi
pmonths=0
如果($x>$W))
然后
pmonths=$($年*12))
echo“离复活节还有$pmon个月。”
其他的
pmonths=$($year1*12))
echo“$x的复活节已经过去了$P个月。”
fi
#检查并计算当前年份和所选年份之间的闰年和正常年份数
计数器=1
leapycounter=0
nycounter=0
如果($x>$W))
然后
而(($计数器<$年))
做
leapy=$($x+$counter))
如果($leapy==($leapy/4)-($leapy/100)+($leapy/400)))
然后leapycounter=$($leapycounter+1))
else nycounter=$($nycounter+1))
fi
计数器=$($计数器+1))
完成
fi
#检查当前年份是否为闰年,以便计算今年剩余的天数
如果($x>$W))
然后
datenow=$(日期+%j)
datenow=`echo$datenow | sed's/^0*/'`
如果($earnow==($earnow/4)-($earnow/100)+($earnow/400)))
然后
datenow=$((366-$datenow))
其他的
datenow=$((365-$datenow))
fi
datethen=$(日期--date=“$x-$N-$P”+%j)
datethen=`echo$datethen | sed's/^0*/'`
天数=$($datethen+$datenow))
lyc=$($leapycounter*366)+($nycounter*365)))
dayspassed=$($lyc+$days))
echo“复活节前有$dayspacsed天。”
其他的
datethen=$(日期--date=“$x-$N-$P”+%j)
datethen=`echo$datethen | sed's/^0*/'`
如果($earnow==($earnow/4)-($earnow/100)+($earnow/400)))
然后
datethen=$((366-$datethen))
其他的
datethen=$((365-$datethen))
fi
datenow=$(日期+%j)
datenow=`echo$datenow | sed's/^0*/'`
天数=$($datethen+$datenow))
lyc=$($leapycounter*366)+($nycounter*365)))
dayspassed=$($lyc+$days))
echo“$days自复活节以来,$x中已过去了几天。”
fi
#这应该将天转换为年、月和天
dtomconst=$((((365/12)*3)+(366/12))/4))
月份=$($dayspassed/$dtomconst))
monthslight=$($months%12))
年=$($月/12))
daysleft=$(($dayspassed-($monthslight*$dtomconst))-(365*$years)))
echo“月是$month”
echo“daysleft是$daysleft”
回音$年
月数=$($月数+$月数左))
回声$monthslight
echo“计算后的月份:$months”
所以问题是它没有正确地计算天数,特别是在过去的几年里。此外,如果用户输入1888年这样的年份,脚本会显示一个错误,我不知道为什么。
如果有人能对我的问题说一两句话,我将非常感激。提前感谢您。

正如评论中所指出的,脚本的挑战在于确定某一年复活节的日期,因为该日期每年都会有所不同,因为每年的时间顺序都是几周。使差异计算更加复杂的是月份的概念,因为闰年会改变二月的长度。还有偶尔的
leap second
,这是一个很好的衡量标准

但是,正如评论中所指出的,一旦您在给定年份到达复活节,您可以让
date
函数为您完成大部分剩余工作。给定任何日期,您都可以将该值传递给
date
函数,并将该值转换为自历元起的秒数。请注意,这对1970年以前的年份没有直接帮助,但您可以将每年的秒数作为近似值进一步向后延伸

一旦你过了复活节,用
日期
获取当前时间(以从纪元开始的秒数表示)就很简单了。然后,您就有了不同的处理方式,可以转换表示从所选复活节到现在的时间的秒数,这些秒数可以用
年、天、小时、分钟、秒来表示。当然,根据所需的精确性水平,必须对其进行扩充,以说明
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

找到复活节有点难。您需要一个自包含的可测试脚本/函数来生成给定年份的复活节。根据我的资料中确定复活节的注释,看起来你在使用O'Beirne算法:基于2001年3月《科学美国人》数学版中对复活节的讨论