#!/bin/sh
#
#	Copyright (c) 1986-2002, Hiram Clawson - curator@hiram.ws.NoSpam
#	All rights reserved.
#
#	Redistribution and use in source and binary forms, with or
#	without modification, are permitted provided that the following
#	conditions are met:
#
#		Redistributions of source code must retain the above
#		copyright notice, this list of conditions and the
#		following disclaimer.
#
#		Redistributions in binary form must reproduce the
#		above copyright notice, this list of conditions and
#		the following disclaimer in the documentation and/or
#		other materials provided with the distribution.
#
#		Neither name of The Museum of Hiram nor the names of
#		its contributors may be used to endorse or promote products
#		derived from this software without specific prior
#		written permission. 
#
#	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
#	CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
#	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#	MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
#	IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
#	INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
#	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
#	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
#	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
#	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
#	THE POSSIBILITY OF SUCH DAMAGE. 
#
#
#	CalDate computes the day of the week, the day of the year
#	the gregorian (or julian) calendar date and the universal
#	time from the julian decimal date.
#	for astronomical purposes, The Gregorian calendar reform occurred
#	on 15 Oct. 1582.  This is 05 Oct 1582 by the julian calendar.
#
#	Input:	a ut_instant structure pointer, where the j_date element
#		has been set. ( = 0 for 01 Jan -4712 12 HR UT )
#
#	output:  will set all the other elements of the structure.
#		As a convienence, the function will also return the year.
#
#	Reference: Astronomial formulae for calculators, meeus, p 23
#	from fortran program by F. Espenak - April 1982 Page 277,
#	50 Year canon of solar eclipses: 1986-2035
#
#
#
#	The structure of a date is:

#typedef struct ut_instant {
#	double	j_date; /* julian decimal date, 0 = 01 Jan -4712 12 HR UT */
#	long year; /* year, valid range [-4,712, +2,147,483,647] */
#	int	month;	/*	[1-12]	*/
#	int	day;	/*	[1-31]	*/
#	int	i_hour;	/*	[0-23]	*/
#	int	i_minute;	/*	[0-59]	*/
#	double	second;	/*	[0-59.9999]	*/
#	double	d_hour;		/* [0.0-23.9999] includes minute and second */
#	double	d_minute;	/*	[0.0-59.9999] includes second	*/
#	int	weekday;	/*	[0-6]	*/
#	int	day_of_year;	/*	[1-366]	*/
#} UTinstant, * UTinstantPtr;

Version() {
echo "dbd.awk - version 1.3 - 2002/11/11 11:11:11 UTC - JD 2452589.966100"
echo "\t%Copyright(C) 1999, 2000, 2001, 2002 - curator@hiram.ws"
}

Usage() {
	echo "usage: dbd.awk <julian date>"
	Version
	exit 0
}

if [ $# -ne 1 ]; then
	JD=2440588.000000		# default is 1970/01/01 12:00:00
else
	JD=$1
fi

while [ $# -gt 0 ]
do
case $1 in
	-h|--h|-help|--help) Usage
		;;
	-v|--v|-version|--version) Version
		;;
	*) JD=$1
		;;
esac
shift
done

TODAY=`./jday.awk 2>&1`

echo "$TODAY" "$JD" | awk '

func CalDate( date_cd ) {

	jd_cd = int(date_cd[j_date_i] + 0.5); #	/* integer julian date */
	frac_cd = date_cd[j_date_i] + 0.5 - jd_cd + 1.0e-10; #/* day fraction */
	ka_cd = int(jd_cd);
	if ( jd_cd >= 2299161 )
	{
		ialp_cd = int(( jd_cd - 1867216.25 ) / ( 36524.25 ));
		ka_cd = int(jd_cd + 1 + ialp_cd - ( int(ialp_cd / 4) ));
	}
	kb_cd = ka_cd + 1524;
	kc_cd = int(( kb_cd - 122.1 ) / 365.25);
	kd_cd = int(kc_cd * 365.25);
	ke_cd = int(( kb_cd - kd_cd ) / 30.6001);
	date_cd[day_i] = kb_cd - kd_cd - int( ke_cd * 30.6001 );

	if ( ke_cd > 13 ) { date_cd[month_i] = ke_cd - 13;
	} else { date_cd[month_i] = ke_cd - 1; }

	if ( (date_cd[month_i] == 2) && (date_cd[day_i] > 28) ) date_cd[day_i] = 29;

	if ( (date_cd[month_i] == 2) && (date_cd[day_i] == 29) && (ke_cd == 3) ) {
		date_cd[year_i] = kc_cd - 4716;
	} else { if ( date_cd[month_i] > 2 ) { date_cd[year_i] = kc_cd - 4716;
		} else { date_cd[year_i] = kc_cd - 4715; }
	}

	date_cd[d_hour_i] = frac_cd * 24.0;	#/* hour */
	date_cd[i_hour_i] = int(date_cd[d_hour_i]);
	date_cd[d_minute_i] = ( date_cd[d_hour_i] - date_cd[i_hour_i] ) * 60.0; # /* minute */
	date_cd[i_minute_i] = int(date_cd[d_minute_i]);
	date_cd[second_i] = 60.0 * \
		(date_cd[d_minute_i] - date_cd[i_minute_i] ); #/* second */
	date_cd[weekday_i] = int((jd_cd + 1) % 7);	# /* day of week */
	if ( date_cd[year_i] == int(((int(date_cd[year_i] / 4)) * 4)) ) {
		date_cd[day_of_year_i] = ( ( 275 * date_cd[month_i] ) / 9) \
			- ((date_cd[month_i] + 9) / 12) \
			+ date_cd[day] - 30;
	} else {
		date_cd[day_of_year_i] = int( ( 275 * date_cd[month_i] ) / 9) \
			- int(((date_cd[month_i] + 9) / 12) * 2) \
			+ date_cd[day] - 30;
	}
	return( date_cd[year_i] );
}	#	/*	end of	 long CalDate( date )	*/

#
#	JulDate computes the julian decimal date (j_date) from
#	the gregorian (or Julian) calendar date.
#	for astronomical purposes, The Gregorian calendar reform occurred
#	on 15 Oct. 1582.  This is 05 Oct 1582 by the julian calendar.
#	Input:  a ut_instant structure pointer where Day, Month, Year and
#		i_hour, i_minute, second have been set for the date
#		in question.
#
#	Output: the j_date and weekday elements of the structure will be set.
#		Also, the return value of the function will be the j_date too.
#
#	Reference: Astronomial formulae for calculators, meeus, p 23
#	from fortran program by F. Espenak - April 1982 Page 276,
#	50 Year canon of solar eclipses: 1986-2035
#

func JulDate( date_jd ) {

	# /* decimal day fraction	*/
	frac_jd = (date_jd[i_hour_i]/ 24.0) \
		+ (date_jd[i_minute_i] / 1440.0) \
		+ (date_jd[second_i] / 86400.0);
	# /* convert date to format YYYY.MMDDdd	*/
	gyr_jd = date_jd[year_i] + (0.01 * date_jd[month_i]) \
		+ (0.0001 * date_jd[day_i]) \
		+ (0.0001 * frac_jd) + 1.0e-9;
	# /* conversion factors */
	if ( date_jd[month_i] <= 2 )
	{
		iy0_jd = date_jd[year_i] - 1;
		im0_jd = date_jd[month_i] + 12;
	}
	else
	{
		iy0_jd = date_jd[year_i];
		im0_jd = date_jd[month_i];
	}
	ia_jd = int(iy0_jd / 100);
	ib_jd = int(2 - ia_jd + int(ia_jd / 4));
	# /* calculate julian date	*/
	if ( date_jd[year_i] <= 0 )
		jd_jd = int(((365.25 * iy0_jd) - 0.75)) \
			+ int((30.6001 * (im0_jd + 1) )) \
			+ int(date_jd[day_i] + 1720994);
	else
		jd_jd = int((365.25 * iy0_jd)) \
			+ int((30.6001 * (im0_jd + 1))) \
			+ int(date_jd[day_i] + 1720994);
	if ( gyr_jd >= 1582.1015 )	# /* on or after 15 October 1582	*/
		jd_jd += ib_jd;
	date_jd[j_date_i] = jd_jd + frac_jd + 0.5;
	jd_jd = int((date_jd[j_date_i] + 0.5));
	date_jd[weekday_i] = int((jd_jd + 1) % 7);
	return( date_jd[j_date_i] );
}	#	/*	end of	double JulDate( date )	*/

func PrintDate ( d ) {
	printf( "jd: %.6f = ", d[j_date_i] );
	printf( "%d/%02d/%02d %02d:%02d:%02d\n", d[year_i], d[month_i], \
		d[day_i], d[i_hour_i], d[i_minute_i], \
		int(d[second_i] + 0.5) );
}
func ZeroDate ( d ) {
	d[j_date_i] = 0.0;
	d[year_i] = 0; d[month_i] = 0; d[day_i] = 0; d[i_hour_i] = 0;
	d[i_minute_i] = 0; d[second_i] = 0; d[d_hour_i] = 0.0
	d[d_minute_i] = 0.0; d[weekday_i] = 0; d[day_of_year_i] = 0;
}
#
#	Define our structure with array indices
#
BEGIN { j_date_i = 1; year_i = 2; month_i = 3; day_i = 4;
	i_hour_i = 5; i_minute_i = 6; second_i = 7; d_hour_i = 8;
	d_minute_i = 9; weekday_i = 10; day_of_year_i = 11;

	test_jd[j_date_i] = 0.0;
	ZeroDate(test_jd);
}
{
	if ( $1 > $2 ) {
		now[j_date_i] = $1;
		then[j_date_i] = $2;
		ET = $1 - $2;
	} else {
		now[j_date_i] = $2;
		then[j_date_i] = $1;
		ET = $2 - $1;
	}
	CalDate(now);
	CalDate(then);
	printf ("%d days = %d weeks =", int(ET), int(ET/7) );
	if ( now[day_i] < then[day_i] ) {
		previous_month[j_date_i] = now[j_date_i] - now[day_i];
		CalDate(previous_month);
		ET_days = previous_month[day_i] + now[day_i] - then[day_i];
		if ( previous_month[month_i] < then[month_i] ) {
			ET_months = 12 + previous_month[month_i] - then[month_i];
			ET_years = previous_month[year_i] - then[year_i] - 1;
		} else {
			ET_months = previous_month[month_i] - then[month_i];
			ET_years = previous_month[year_i] - then[year_i];
		}
	} else {
		ET_days = now[day_i] - then[day_i];
		if ( now[month_i] < then[month_i] ) {
			ET_months = 12 + now[month_i] - then[month_i];
			ET_years = now[year_i] - then[year_i] - 1;
		} else {
			ET_months = now[month_i] - then[month_i];
			ET_years = now[year_i] - then[year_i];
		}
	}
	ET_weeks = int(ET_days/7);
	ET_days = ET_days - (ET_weeks*7);
	if ( ET_years ) {
		if ( 1 == ET_years ) {
			printf ( " %d year", ET_years );
		} else {
			printf ( " %d years", ET_years );
		}
	}
	if ( ET_years && ((ET_weeks == 0) && (ET_days == 0)) ) {
		printf " and"
	}
	if ( ET_months ) {
		if ( 1 == ET_months ) {
			printf ( " %d month", ET_months );
		} else {
			printf ( " %d months", ET_months );
		}
	}
	if ( ET_months && ET_weeks  && (ET_days == 0) ) {
		printf " and"
	}
	if ( ET_weeks ) {
		if ( 1 == ET_weeks ) {
			printf ( " %d week", ET_weeks );
		} else {
			printf ( " %d weeks", ET_weeks );
		}
	}
	if ( ET_days ) {
		if ( 1 == ET_days ) {
			if ( ET_years || ET_months || ET_weeks ) {
				printf ( " and a day" );
			} else {
				printf ( " one day" );
			}
		} else {
			if ( ET_years || ET_months || ET_weekss ) {
				printf ( " and %d days", ET_days );
			} else {
				printf ( " %d days", ET_days );
			}
		}
	}
	printf (".\n");
}'
