Vi har virkelig ikke (endnu) har en udstationering, som tager fat om det generelle problem med antallet af dage mellem to datoer. Så jeg har netop færdig med det, der skulle være den sidste beregning script at jeg nogensinde skrive. Den matematiske gav mig passer og jeg er ikke sikker på, at jeg har denne ret endnu. Men her er det alligevel. Nogle eksempler på, hvad den kan gøre ...
> Datecalc-a 1960 12 31 - 1922 2 2
14212
> Datecalc-a 1960 12 31 + 7
1961 1 7
> Datecalc-D 1960 12 31
Lørdag
Jeg har netop revideret dette script. Jeg har tilføjet en-l mulighed for at beregne den sidste dag i måneden. Jeg har tilføjet en funktion til at gøre dette og ændrede date2jd funktion at bruge denne nye funktion. Jeg forbedret fejlmeddelelser og tilføjede en-help mulighed for at forhåbentlig gøre datecalc selvstændig dokumentation.
Som før, hvis du finder nogen fejl så lad mig det vide. Ans hvis finde nogen dato manipulation behovet for, at den ikke kan gøre, så lad mig det vide, at så godt. Jeg er stadig håb, at dette script kan løse alle dato manipulation problemer.
Her er den nye version ...
Code:
#! /usr/bin/ksh
# datecalc -- Perderabo's date calculator
#
USAGE="\
datecalc -a year month day - year month day
datecalc -a year month day [-|+] n
datecalc -d year month day
datecalc -D year month day
datecalc -j year month day
datecalc -j n
datecalc -l year month
use \"datecalc -help\" use for more documentation"
DOCUMENTATION="\
datecalc Version 1.1
datecalc does many manipulations with dates.
datecalc -a is for date arithmetic
datecalc -d or -D converts a date to the day of week
datecalc -j converts to date to or from julian day
datecalc -l outputs the last day of a month
All dates must be between the years 1860 and 3999.
datecalc -a followed by 7 parameters will calculate the
number of days between two dates. Parameters 2-4 and 6-8
must be dates in ymd form, and parameter 5 must be a minus
sign. The output is an integer. Example:
> datecalc -a 1960 12 31 - 1922 2 2
14212
datecalc -a followed by 5 parameters will calculate the
a new date offset from a given date, Parameters 2-4 must
be a date in ymd form, paramter 5 must be + or -, and
paramter 6 must be an integer. Output is a new date.
Example:
> datecalc -a 1960 12 31 + 7
1961 1 7
datecalc -d followed by 3 parameters will convert a date
to a day-of-week. Parameters 2-4 must be a date in ymd
form. Example:
> datecalc -d 1960 12 31
6
datecalc -D is like -d except it displays the name of
the day. Example:
> datecalc -D 1960 12 31
Saturday
datecalc -j followed by 3 parameters will convert a date
to Modified Julian Day number. Example:
> datecalc -j 1960 12 31
37299
datecalc -j followed by a single parameter will convert
a Modified Julian Day number to a date. Example:
> datecalc -j 37299
1960 12 31
datecalc -l followed by year and month will output the last
day of that month. Note that by checking the last day of
February you can test for leap year. Example:
> datecalc -l 2002 2
28"
lastday() {
integer year month leap
# ja fe ma ap ma jn jl ag se oc no de
set -A mlength xx 31 28 31 30 31 30 31 31 30 31 30 31
year=$1
if ((year<1860 || year> 3999)) ; then
print -u2 year out of range
return 1
fi
month=$2
if ((month<1 || month> 12)) ; then
print -u2 month out of range
return 1
fi
if ((month != 2)) ; then
print ${mlength[month]}
return 0
fi
leap=0
if ((!(year%100))); then
((!(year%400))) && leap=1
else
((!(year%4))) && leap=1
fi
feblength=28
((leap)) && feblength=29
print $feblength
return 0
}
date2jd() {
integer ijd day month year mnjd jd lday
year=$1
month=$2
day=$3
lday=$(lastday $year $month) || exit $?
if ((day<1 || day> lday)) ; then
print -u2 day out of range
return 1
fi
((standard_jd = day - 32075
+ 1461 * (year + 4800 - (14 - month)/12)/4
+ 367 * (month - 2 + (14 - month)/12*12)/12
- 3 * ((year + 4900 - (14 - month)/12)/100)/4))
((jd = standard_jd-2400001))
print $jd
return 0
}
jd2dow()
{
integer jd dow numeric_mode
set +A days Sunday Monday Tuesday Wednesday Thursday Friday Saturday
numeric_mode=0
if [[ $1 = -n ]] ; then
numeric_mode=1
shift
fi
jd=$1
if ((jd<1 || jd>782028)) ; then
print -u2 julian day out of range
return 1
fi
((dow=(jd+3)%7))
if ((numeric_mode)) ; then
print $dow
else
print ${days[dow]}
fi
return
}
jd2date()
{
integer standard_jd temp1 temp2 jd year month day
jd=$1
if ((jd<1 || jd>782028)) ; then
print julian day out of range
return 1
fi
((standard_jd=jd+2400001))
((temp1 = standard_jd + 68569))
((temp2 = 4*temp1/146097))
((temp1 = temp1 - (146097 * temp2 + 3) / 4))
((year = 4000 * (temp1 + 1) / 1461001))
((temp1 = temp1 - 1461 * year/4 + 31))
((month = 80 * temp1 / 2447))
((day = temp1 - 2447 * month / 80))
((temp1 = month / 11))
((month = month + 2 - 12 * temp1))
((year = 100 * (temp2 - 49) + year + temp1))
print $year $month $day
return 0
}
#
# Parse parameters and get to work.
case $1 in
-a) if (($# == 8)) ; then
if [[ $5 != - ]] ; then
print -u2 - "$USAGE"
exit 1
fi
jd1=$(date2jd $2 $3 $4) || exit $?
jd2=$(date2jd $6 $7 $8) || exit $?
((jd3=jd1-jd2))
print $jd3
exit 0
elif (($# == 6)) ; then
jd1=$(date2jd $2 $3 $4) || exit $?
case $5 in
-|+) eval '(('jd2=${jd1}${5}${6}'))'
jd2date $jd2
exit $?
;;
*)
print -u2 - "$USAGE"
exit 1
;;
esac
fi
;;
-d|-D) if (($# != 4)) ; then
print -u2 - "$USAGE"
exit 1
fi
jd1=$(date2jd $2 $3 $4) || exit $?
numeric=-n
[[ $1 = -D ]] && numeric=""
eval jd2dow $numeric $jd1
exit $?
;;
-j) if (($# == 4)) ; then
date2jd $2 $3 $4
exit $?
elif (($# == 2)) ; then
jd2date $2 $3 $4
exit $?
else
print -u2 - "$USAGE"
exit 1
fi
;;
-l) if (($# == 3)) ; then
lastday $2 $3
exit $?
else
print -u2 - "$USAGE"
exit 1
fi
;;
-help) print - "$USAGE"
print ""
print - "$DOCUMENTATION"
exit 0
;;
*) print -u2 - "$USAGE"
exit 0
;;
esac
#not reached
exit 7