I keep getting into a situation where I need to do some simple date calculations. This is not a problem using a language like Java or when using a language that lets you add additional modules like Perl. Unfortunately, some of the tasks I get at work don’t allow me the luxury of choosing which technologies are available to me.
Yet the algorithms themselves are usually pretty well defined and can be recreated in a different language if needed by. In this particular case, the problems of calculating using dates is not unique and has been solved a long time a ago by astronomers. The solution was to start counting at zero at the beginning of the calendar and each day following day is increased by an additional value.
The Julian Day Number (JDN) is the integer assigned to a whole solar day in the Julian day count starting from noon Greenwich Mean Time, with Julian day number 0 assigned to the day starting at noon on January 1, 4713 BC, proleptic Julian calendar
This is all described on the wikipedia webpage, but more interesting than knowing how astronomers thought about their problems is all of their calculations that allow you to convert your normal Gregorian date into a Juliane Day Number.
Once the date is converted, you can then do simple math between the two dates to find the difference in days. It is a simple matter of adding a integer to see what the date is after that calculation or even what day of the week that day is.
A bash script that can do date calculations may not necessarily be the most efficient technology decision, but it is portable and when not needed for high volume processing may be right solution for a particular job.
Besides, it is fun and all that is necessary is the ability to perform a few calculations, I have a small explanation of both floating point and integer math in bash in another article.
#!/bin/bash
# https://en.wikipedia.org/wiki/Julian_day#Converting_Julian_or_Gregorian_calendar_date_to_Julian_day_number
# div = floor(dividend / divisor)
div()
{
echo $(( $1 / $2 ))
}
# quotient = dividend / divisor
modulo()
{
echo $(($1 % $2))
}
# the lowest whole number
floor()
{
X=$1
echo ${X%.*}
}
#####################################################################################################
# #
# a = floor ((14 - month)/12) #
# y = year + 4800 - a #
# m = month + 12a - 3 #
# #
# aa bb cc dd ee ff gg #
#JDN = day + floor ((153m + 2) / 5) + 365y + floor (y/4) - floor (y/100) + floor (y/400) - 32045 #
#####################################################################################################
getJulian()
{
YEAR=$1
MONTH=$2
DAY=$3
a=`echo "(14 - $MONTH) / 12" | bc -l`
a=`echo 0${a}`
a=`floor $a`
y=`echo $YEAR + 4800 - $a | bc -l`
m=`echo "$MONTH + 12 * $a - 3" | bc -l`
#echo a $a
#echo y $y
#echo m $m
aa=$DAY
#echo aa $aa
bb=`echo "(( 153 * $m + 2) / 5)" | bc -l `
bb=`floor $bb`
#echo bb $bb
cc=`echo "365 * $y" | bc -l`
#echo cc $cc
dd=`echo "$y / 4" | bc -l`
dd=`floor $dd`
#echo dd $dd
ee=`echo "$y / 100" | bc -l`
ee=`floor $ee`
#echo ee $ee
ff=`echo "$y / 400" | bc -l`
ff=`floor $ff`
#echo ff $ff
gg=32045
#echo gg $gg
JDN=`echo "$aa + $bb + $cc + $dd - $ee + $ff - $gg" | bc -l`
#echo JDN $JDN
echo $JDN
}
day=1
month=1
year=2000
val=`getJulian $year $month $day`
echo $val
echo .
for i in 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
do
val=`getJulian $year $month $i`
echo $val
done
This is not the only formula to do the conversion from a Gregorian date to a Juliane day number.
Depending on the sources of your algorithm not all Julian day numbers will be compatible.