It does exactly what those commands do. Just that we dont have GNU 'date' and aren't allowed to install that either. So I came up with this. Just that the extreme cases like a difference of 100000 days takes a lot of time. Here is the output of uname -a:
SunOS xxxxxxx 5.8 Generic_117350-24 sun4u sparc SUNW,Ultra-Enterprise
There is almost no load on the server (uptime reports 0.06...).
Here are some 'time' command outputs for my script.
# time ./tonfro.sh 100
2005-11-11
real 0m0.31s
user 0m0.08s
sys 0m0.20s
# time ./tonfro.sh 10000
2032-12-19
real 0m7.84s
user 0m2.49s
sys 0m4.81s
# time ./tonfro.sh 100000
2279-05-19
real 1m16.19s
user 0m23.08s
sys 0m47.55s
--EDIT--
Is $() valid in sh? I am not using ksh. Also, assuming it is valid, will it run any faster than expr?
--/EDIT
Arithmetic Expansion
Arithmetic expansion allows the evaluation of an arithmetic expression
and the substitution of the result. The format for arithmetic expan-
sion is:
$((expression))
The expression is treated as if it were within double quotes, but a
double quote inside the parentheses is not treated specially. All
tokens in the expression undergo parameter expansion, string expansion,
command substitution, and quote removal. Arithmetic substitutions may
be nested.
The evaluation is performed according to the rules listed below under
ARITHMETIC EVALUATION. If expression is invalid, bash prints a message
indicating failure and no substitution occurs.
How about combining the first two conditions into 1 ?
if [ `expr $year % 100` -eq 0 -a `expr $year % 400` -eq 0 ]
then
daysofmth=29
elif [ `expr $year % 100` -ne 0 -a `expr $year % 4` -eq 0 ]
then
daysofmth=29
else
daysofmth=28
fi
to
if [ (($(($year % 100)) -eq 0 -a $(($year % 400)) -eq 0)) -o \
(($(($year % 100)) -ne 0 -a $(($year % 4)) -eq 0)) ]
then
daysofmth=29
else
daysofmth=28
fi
Haven't tested it tho'.
Aided by man sh
((expression))
The expression is evaluated according to the rules described
below under ARITHMETIC EVALUATION. If the value of the expres-
sion is non-zero, the return status is 0; otherwise the return
status is 1. This is exactly equivalent to let "expression".
Apparently it was the 'expr' command that was slowing things down. I changed to '#!/usr/bin/ksh' and got a major speed up!
Here are the new 'time' outputs:
Doesn't anyone read the faqs? Look up Yesterdays Date/Date Arithmetic which mentions my script called datecalc. Switch to that and see what timings you get.
Perderabo,
I know that your script is blinding quick (literally.. over a 1000 times faster). But you seem to be using some arithmetic that fits for your date range. Can you explain what exactly you are using?
I got that formula on the internet. Actually I got several that did the same thing, timed them, and picked the fastest. I don't know why it works. But I do that that it works. I used the forumula to compute the mjd of of the first date in my range. Then I incremented the the calendar date and recomputed the mjd and verified that it increased by one. So the forumla works over the entire range that I support. I needed a finite range to run that verification. Where the range came from: 1860 is the first year that Alaska used the Gregorian calendar. Prior to that, it followed Russia which was on the old Julian calendar. So in 1860, for the first time, no Julian calendar was in use anywhere in the USA. 3999 is the last year where there is unanimous agreement in the calculation of leap year. I didn't want to join the year 4000 fight.
Another way to cumpute any date in the past or in the future from today :
#------------------------------------------------------------------------
# Fonction .. : getDate [days [format]]
# Args ...... : $1 = days : Offet from today [+|-]n (def=0)
# $2 = format : Format for the date display
# Example ... : o Yesterday => GetDate -1
# o Tomorrow, yyyymmdd => GetDate +1 '+%Y%m%d'
#------------------------------------------------------------------------
function getDate { # GetDate days [format]
l_days=0
l_format=''
if [ $# -ge 1 ]
then
l_days=$1
shift
fi
l_format="$*"
l_local_offset=$(echo $TZ | sed 's![^-0-9]*\([-0-9]*\).*!\1!')
l_new_offset=`expr $l_local_offset - 24 \* $l_days`
l_new_tz="`echo $TZ | sed 's!^\([^-0-9]*\)[-0-9]*\(.*\)$!\1'${l_new_offset}'\2!'`"
TZ="$l_new_tz" date "$l_format"
unset l_days l_format l_local_offset l_new_offset l_new_tz
}
######### main script starts here
if [ $# -ne 1 ]
then
echo "Usage: tonfro <delta>"
exit 1
fi
getDate $1 '+%Y-%m-%d'
On my AIX box, the offset is limited in days to the range [-37854,+1855].
The original KSH GetDate function was written by PHV in the 'Unix Scripting FAQ' of www.tek-tips.com