[comp.sources.misc] v17i083: calentool - day/week/month/year-at-a-glance SunView tool, Part02/23

billr@saab.CNA.TEK.COM (Bill Randle) (04/04/91)

Submitted-by: Bill Randle <billr@saab.CNA.TEK.COM>
Posting-number: Volume 17, Issue 83
Archive-name: calentool/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 23)."
# Contents:  Fixes1_3 Patches2_1 datelib.c
# Wrapped by billr@saab on Thu Mar 28 08:38:11 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Fixes1_3' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Fixes1_3'\"
else
echo shar: Extracting \"'Fixes1_3'\" \(228 characters\)
sed "s/^X//" >'Fixes1_3' <<'END_OF_FILE'
X# $Header: Fixes1_3,v 1.1 88/04/08 11:27:57 billr Exp $
X
XVersion 1.3 update:
X
X1) Add code to handle command line arguments (mainly because I
X   like it to come up iconic and put the icon where I want it).
X
X	-Bill Randle
X	2/3/88
END_OF_FILE
if test 228 -ne `wc -c <'Fixes1_3'`; then
    echo shar: \"'Fixes1_3'\" unpacked with wrong size!
fi
# end of 'Fixes1_3'
fi
if test -f 'Patches2_1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Patches2_1'\"
else
echo shar: Extracting \"'Patches2_1'\" \(6274 characters\)
sed "s/^X//" >'Patches2_1' <<'END_OF_FILE'
X# $Header: Patches2_1,v 2.7 90/01/04 15:08:48 billr Exp $
X
X#$Log:	Patches2_1,v $
X# Revision 2.7  90/01/04  15:08:48  billr
X# Patchlevel 6 of calentool fixes the following bugs:
X# 
X#===========
X#Bugs Fixed:
X#===========
X#Fix bug where holidays are not shown in the day display if there
X#	are no regular appointments for that day. <smb@research.att.com>,
X#	<phil@grumpy.cgrg.ohio-state.edu>
X#Fix bug that caused the year display to be off by one on its display.
X#	<seamans@seaimage@nlm.nih.gov>, <shen@burma.crd.ge.COM>
X#Fixed typos in the world and space date files. <rodgers@maxwell.mmwb.ucsf.edu>
X#Added a warning to the Makefile regarding optimizing the "wpaint.c" file.
X#	<seamans@seaimage@nlm.nih.gov>
X#
X# Revision 2.6  89/12/15  17:13:23  billr
X# Patchlevel 5 of calentool fixes the following bugs and adds features:
X# 
X# ===========
X# Bugs Fixed:
X# ===========
X# calentool -p -m misses warnings in advance if the warning and 
X# 	appointments are in different month.  <kayhan@eve.usc.edu>
X# Fixed bug with day/week PostScript printouts [reported by several people]
X# Fixed bug with "-m" option [reported by several people]
X# Corrected date for Australia Day <ajc@philabs.philips.COM>
X# Fixed -p/-P/-m options so nothing is printed (or mailed) if there are
X# 	no appointments for the day. <uunet.uu.net!xlab!milt!milt>, <brooks@ge-dab.crd.ge.COM>
X# Fixed bug whereby entire calentool was being changed to black&white
X# 	after the Moon data frame was displayed.
X# Fixed bug in calculation of Jewish passover (on which all the other
X# 	Jewish holidays are based) <smb@hector.att.COM>, <rjc@cs.brown.edu>
X# Fixed bug that displayed previous days calendar if a day is selected from a 6 day week. <bob@omni.COM>
X# Shortend length of an extra long entry in the dates/space file. <cdurst@aecmail.prime.com>
X# Fixed bug in calculation of nth_day_of_month (shows up as putting election
X# 	day on the wrong week). <uunet.uu.net!formtek!pen>, <att.att.COM!cbosgd!smk>
X# Fixed bug whereby deleted repeated appointments were not always recognized.
X# Added #define for mail program with default set to "usr/ucb/mail". The
X# 	problem showed up when a user had /usr/5bin in his path before
X# 	/usr/ucb. <uunet.uu.net!cjsa!jeff>
X# Fixed bug that caused calentool to dump core on notes sections with long messages.
X# Added dates/space entry in Makefile.
X# 
X# =============
X# New features:
X# =============
X# Modified parse_date to allow +nnn and -nnn syntax for dates relative to the
X# 	current date. <peter@hadrian.uwo.ca>
X# 
X# Add new #defines and switches for selected 12/24 time displays and either
X# 	Sunday-Saturday or Monday-Sunday weeks (for some Europeans). <hk@simulina.se>
X# Cleaner opening windows. <cdurst@aecmail.prime.com>
X# New -B option to beep AND open calentool window. <cdurst@aecmail.prime.com>
X# Nested includes (to 4 levels) are now allowed. (Idea from <mdf0%shemesh@gte.COM>)
X# Allow -p/-P[dw] options to work in conjunction with -m/-M so that a
X# 	weeks worth of appointments can be mailed.
X# Added new expire option (-x) to expire (trash) all appointments older than
X# 	a specified number of days.
X# The sense of the -w option was changed. In order to get the "Working!"
X# 	message, you now have to specify "-w".
X# Changed M/D/Y dates to D/M/Y when European option (-E) selected.
X# Optimized certain holiday calculations.
X# New feature for appointments that repeat for a fixed interval of time
X#       e.g. 12/26/89 for 5 days.
X# Wrote new calencheck program for checking for pending appts without having
X# 	to run calentool.
X#
X# Revision 2.5  89/09/19  06:17:10  billr
X# Patchlevel 4 of calentool. Fixes the following bug reports:
X# 
X# Bug fix in pcal.c for printing month of September <alexl@daemon.cna.tek.com>
X# Bug fix for 386i machines when viewing long appointment strings <baron@neptune.cs.ucla.edu>
X# Fix typos and clean up man page <rodgers@maxwell.mmwb.ucsf.edu>
X# 
X# Revision 2.4  89/08/11  08:34:47  billr
X# Patchlevel 3 of calentool. Fixes the following bug reports:
X# 
X# Bug fix for moontool <kelvin%throop@acad.uucp>
X# Bug fix/new version of passover() <amos@nsc.com>
X# Bug in moon phase calculation <kent@tfd.com>, <ras@needle1.bellcore.com>, <roberts%studguppy@lanl.gov>, <darcic@lachlan.sts.te.com>
X# Check return from get_defaults <ian@sq.com>
X# Cleanup Makefile <casey@gauss.llnl.gov>
X# Idea for monthly printout for terminal users <ian@sq.com>
X# Makefile did not copy dates/computing to lib dir <jmc@ptsfa.pacbell.com>
X# Missing arg for rotate function in ras2ps <jasmerb@hobbes.cs.orst.edu>
X# More makefile cleanup <lwv27%chemabs@cis.ohio-state.edu>
X# Off by one in mt2ct conversion <tom@cis.udel.edu>, <kas@cs.aber.ac.uk>, <paul%gill@uunet.uu.net>
X# Optimize nr weeks calculation for month display <rwolff@noao.edu>
X# Prevent calentool from sending mail when there are no appts <zander%trak@lanl.gov>, <john@math.nwu.edu>, <kayhan@cleopatra.usc.edu>
X# Raster print command missing '-v' argument <hleroy@presto.irisa.fr>
X# Scrambled moon icon on 386i <scott@cfi.com>, <lwv27%chemabs@cis.ohio-state.edu>, <syd@dsi.com>, <alfred@mcc.com>
X# Seg fault when cursor moved to long appt entry (386i) <alfred@mcc.com>, <jmc@pbjmc.pacbell.com>, <baron@neptune.cs.ucla.edu>
X# Set file access permissions on tmp file to match .appointments file <brooks@ge-dab.ge.com>
X# Space date file <steve@prism.gatech.edu>
X# Typo in man page "Save" file shoudl be "Update" file <lwv27%chemabs@cis.ohio-state.edu>
X# Typo in riseset.c (tzp.minuteswest should be tzp.tz_minuteswest) <hleroy@presto.irisa.fr>, <correira@austin.lockheed.com>
X# When deleteing an overlapping entry, background entry is not displayed <rgh@shell.uucp>
X# Wrong week displayed when selecting a week in month display <rodgers@maxwell.mmwb.ucsf.edu>
X#
X# Revision 2.3  89/05/16  16:32:23  billr
X# Fix bug whereby nfs mounted appointment files were not being
X# properly updated.  Add support for PostScript pretty printing
X# of a month's worth of appointments.
X# 
X# Revision 2.2  89/05/10  10:15:59  billr
X# Fix bug relating to arrow count in the notes field.  It showed up when
X# adding an additional note or pasting an appointment that overran its
X# available timeslots.  Now at version 2.1, patchlevel 1 (V2.1p1).
X# 
X#
X# Revision 2.1  89/05/09  10:13:56  billr
X# release 2.1, patchlevel 0
X# 
END_OF_FILE
if test 6274 -ne `wc -c <'Patches2_1'`; then
    echo shar: \"'Patches2_1'\" unpacked with wrong size!
fi
# end of 'Patches2_1'
fi
if test -f 'datelib.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'datelib.c'\"
else
echo shar: Extracting \"'datelib.c'\" \(44896 characters\)
sed "s/^X//" >'datelib.c' <<'END_OF_FILE'
X/*
X * $Header: datelib.c,v 2.5 91/01/30 12:45:28 billr Exp $
X *
X * datelib.c - Calendar (date) computation library
X *
X * R. P. C. Rodgers, UCSF, November 1988
X * (with thanks to Greg Couch, Conrad Huang, and Dave Yee for their helpful
X *  suggestions)
X *
X *        Copyright 1988, 1989 R. P. C. Rodgers,  All Rights Reserved
X * Permission is granted by the author for use of this code under the following
X * conditions: 1) improvements and corrections to this code are shared with the
X * author; 2) the code is made freely available to anyone requesting it; 3) the
X * code is not used for any profit-making venture without the express
X * permission of the author; and, 3) all copies of the code will preserve the
X * above authorship and copyright information and this notice.
X *
X * (requires math library)
X * 
X * Source of formulae:
X * 
X * 1) Schocken, Wolfgang Alexander
X *    The calculated confusion of calendars; puzzles in Christian, Jewish and
X *       Moslem calendars.
X *    1st Ed.
X *    Vantage Press
X *    New York
X *    1976
X * 
X * 2) Meeus, Jean
X *    Astronomical Formulae for Calculators
X *    Monografieen over Astronomie en Astrofysica
X *    Volkssterrenwacht Urania V.Z.W.
X *    Mattheessensstraat 62, B 2540 Hove, Belgium
X *    Vereniging voor Sterrenkunde V.Z.W.
X *    Ringlaan 3, B 1180 Brussel, Belgium
X *    Vol. 4
X *    Derde Druk
X *    October 1980
X *    (3rd edition of 1985 available from Willmann-Bell, address below)
X *    (formulae for Easter, Julian and Gregorian date formation, and
X *     solstices/equinoxes)
X * 
X * 3) Assorted contributions to the Hewlett-Packard HP-41C Software Library
X * 
X * In his 1987 Sun program "moontool," John Walker (Autodesk, Sausalito, CA)
X * mentions several other potentially useful references:
X * 
X * 4) Pierre Bretagnon and Jean-Louis Simon
X *    Planetary Programs and Tables from -4000 to +2800
X *    Willmann-Bell
X *    1986
X *    (for utmost accuracy in planetary computations)
X * 
X * 5) Eric Burgess
X *    Celestial BASIC
X *    Revised Edition
X *    Sybex
X *    1985
X *    (cookbook oriented, many algorithms hard to dig out of turgid BASIC)
X * 
X * Many of these references can be obtained from Willmann-Bell, P.O. Box
X * 35025, Richmond, VA 23235, USA.  Phone: (804) 320-7016.  In addition
X * to their own publications, they stock most of the standard references
X * for mathematical and positional astronomy.
X * 
X * NOTES:
X * check ranges on days (0-365)
X * islamic new year and jewish dates not thoroughly tested
X * 
X */
X
X#include "ct.h"		/* for the NO_HOLIDAYS #define */
X
X#include	<stdio.h>	/* for NULL */
X#include	<math.h>
X
Xdouble	julian_day();
X
X#ifndef NO_HOLIDAYS
Xextern	char	*malloc();
Xdouble  easter_offset(), passover_offset();
X
Xstatic char	*monthname[] = { 
X		"January", "February", "March", "April", "May",
X		"June", "July", "August", "September",
X		"October", "November", "December"	};
Xstatic char	*dayname[] = { 
X		"Sunday", "Monday", "Tuesday", "Wednesday",
X		"Thursday", "Friday", "Saturday"	};
Xstatic char	timebuf[16];
Xstatic double	passoverJD, easterJD;
Xstatic int	passoverJY;
X
X/*
X * date_string:
X * Return date string of form: "Monday 12 December 1988"
X * given day of week (0-6), day (1-31), month (1-12), year
X */
Xchar *
Xdate_string(day_of_week, day, month, year)
X	double	day;
X	int	day_of_week, month, year;
X{
X	char *date;
X
X	date = (char *) malloc(81 * sizeof(char));
X	if (date == NULL)
X		err_rpt("out of memory", FATAL);
X	(void) sprintf(date, "%s %d %s %d",
X		dayname[day_of_week], (int) day, monthname[--month], year);
X	return date;
X}
X
X/*
X * date_string_2:
X * Return date string of form: "Monday 12 December 1988 (NYEAR)"
X * given day of week (0-6), day (1-31), month (1-12), year, and alternate
X * (that is, non-Gregorian) year, NYEAR
X */
Xchar *
Xdate_string_2(day_of_week, day, month, year, nyear)
X	double	day;
X	int	day_of_week, month, nyear, year;
X{
X	char *date;
X
X	date = (char *) malloc(81 * sizeof(char));
X	if (date == NULL)
X		err_rpt("out of memory", FATAL);
X	(void) sprintf(date, "%s %d %s %d (%d)",
X		dayname[day_of_week], (int) day, monthname[--month],
X			year, nyear);
X	return date;
X}
X
X/*
X * date_time_string:
X * Return date/time string of form: "10:42 Monday 12 December 1988"
X * given hour (0-24), minute (0-59), day of week (0-6), day (1-31),
X * month (1-12), year
X */
Xchar *
Xdate_time_string(hour, min, day_of_week, day, month, year)
X	double	day;
X	int	day_of_week, hour, min, month, year;
X{
X	char *date;
X
X	date = (char *) malloc(81 * sizeof(char));
X	if (date == NULL)
X		err_rpt("out of memory", FATAL);
X	(void) sprintf(date, "%02d:%02d %s %d %s %d",
X		hour, min, dayname[day_of_week], (int) day,
X		monthname[--month], year);
X	return date;
X}
X
X/*
X * election_day:
X * Compute date of Election Day given year (1584-9999)
X * Election day is defined as the first Tuesday following the first
X * Monday in November.
X */
Xdouble
Xelection_day(year)
X	int	year;
X{
X	double day, nth_mday_of_month();
X
X	/* find first Tuesday in Nov. */
X	day = nth_mday_of_month(1, 2, 11, year);
X	/* if it's the first day of the month then Election day is next week */
X	if (day == 1.)
X		day = 8.;
X	return julian_day(day, 11, year);
X}
X
X/*
X * dday2:
X * Compute dday2 for various holiday routines given x value, year (>1583)
X */
Xdday2(x, year)
X	int	x, year;
X{
X	int	atmp, btmp;
X
X	atmp = 1.25 * year;
X	btmp = year / 100;
X	btmp = 0.75 * (1 + btmp);
X	return (x + atmp - btmp) % 7;
X}
X#endif	/* NO_HOLIDAYS */
X
X/*
X * days_remaining_in_year:
X * Compute remaining days of year (0-365)
X * given day (1-31), month (1-12), year (1901-2009)
X */
Xdays_remaining_in_year(day, month, year)
X	double	day;
X	int	month, year;
X{
X	int	length_of_year(), day_of_year();
X
X	return length_of_year(year) - day_of_year(day, month, year);
X}
X
X/*
X * length_of_year:
X * Compute days in year (365 or 366)
X * given year (1901-2009)
X */
Xlength_of_year(year)
X	int	year;
X{
X	int	ylength;
X
X	if ((year % 400) == 0)
X		ylength = 366;
X	else if ((year % 100) == 0)
X		ylength = 365;
X	else if ((year % 4) == 0)
X		ylength = 366;
X	else
X		ylength = 365;
X	return ylength;
X}
X
X/*
X * get_day_of_week:
X * Compute day of week (0-6 for Sunday-Saturday)
X * given day (1-31), month (1-12), year (1901-2009)
X */
Xget_day_of_week(day, month, year)
X	double	day;
X	int	month, year;
X{
X	int	atmp;
X
X	atmp = julian_day(day, month, year) + 1.5;
X	return atmp % 7;
X}
X
X/*
X * day_of_year:
X * Compute day of year (1-366)
X * given day (1-31), month (1-12), year (1901-2009)
X */
Xday_of_year(day, month, year)
X	double	day;
X	int	month, year;
X{
X	return (int) julian_day(day, month, year)
X		- (int) julian_day(0.0, 1, year);
X}
X
X/*
X * nth_mday_of_month:
X * Compute nth m-day of the month (1-31)
X * given n (1-5), day of week (0-6, 0 for Sunday), month (1-12),
X * year (1583-9999)
X */
Xdouble
Xnth_mday_of_month(n, day_of_week, month, year)
X	int	day_of_week, month, n, year;
X{
X	int	atmp, btmp, ctmp, dtmp, etmp, tmonth, tyear;
X
X	if (month > 2) {
X		tmonth = month + 1;
X		tyear = year;
X	}
X	else {
X		tmonth = month + 13;
X		tyear = year - 1;
X	}
X	atmp = 2.6 * tmonth;
X	btmp = 1.25 * tyear;
X	ctmp = (tyear / 100) - 7;
X	dtmp = 0.75 * ctmp;
X	etmp = (day_of_week - atmp - btmp + dtmp) % 7;
X	return (double) (etmp + (n * 7));
X}
X
X/*
X * julian_day:
X * Compute Julian day (>=1)
X * given day (1-31), month (1-12), year (1901-2009)
X *
X * Notes: The Gregorian reform is taken into account (that is, the day
X * following 4 October 1582 is 15 October 1582; dates on this latter day or
X * later are said to be in the Gregorian calendar).  B.C. years are counted
X * astronomically (the year prior to year 1 is year 0).  The Julian day
X * begins at GMT noon (the day is expressed in floating point).
X * Example: to obtain Julian day for 4 Jul 1979: julian_day(4.0, 7, 1979)
X */
Xdouble
Xjulian_day(day, month, year)
X	double	day;
X	int	month, year;
X{
X	int	atmp, monthp, yearp;
X	double	ctmp = 1720994.5 + day;
X
X	if (month > 2) {
X		monthp = month + 1;
X		yearp = year;
X	}
X	else {
X		monthp = month + 13;
X		yearp = year - 1;
X	}
X	if ((year > 1582) || (year == 1582 && month >= 10)
X		|| (year == 1582 && month == 10 && day >= 15)) {
X		atmp = year / 100;
X		ctmp += 2 - atmp + (int)(atmp / 4);
X	}
X	ctmp += (int)(365.25 * yearp) + (int)(30.6001 * monthp);
X	return ctmp;
X}
X
X#ifndef NO_HOLIDAYS
X/*
X * datelib_int:
X * Calculate often used quantities (e.g. Easter, Passover) as an
X * optimization.
X */
Xdatelib_init(year)
X	int	year;
X{
X	void passover_init(), easter_init();
X
X	easter_init(year);
X	passover_init(year);
X}
X
X/*
X * corrected_julian_day:
X * Correct Julian day (>=1) for conversion from JULIAN CALENDAR
X * to GREGORIAN CALENDAR.
X */
Xdouble
Xcorrected_julian_day(jday)
X	double	jday;
X{
X	double	day;
X	int	atmp, btmp, month, year;
X
X	gregorian_date(&day, &month, &year, jday);
X	atmp = year / 100;
X	btmp = ((3 * atmp) - 5) / 4;
X	return julian_day(day, month, year) + btmp;
X}
X
X/*
X * gregorian_date:
X * Return pointers to day (1-31), month (1-12), year (1901-2009),
X * given Julian day (>=0)
X *
X * Notes: The Gregorian reform is taken into account (that is, the day
X * following 4 October 1582 is 15 October 1582; dates on this latter day or
X * later are said to be in the Gregorian calendar).  B.C. years are counted
X * astronomically (the year prior to year 1 is year 0).  The Julian day
X * begins at GMT noon.  The Julian day can be expressed in
X * floating point below to get a day result with decimal places.  This method
X * is valid only for positive Julian day numbers.
X */
Xgregorian_date(p_day, p_month, p_year, jday)
X	int	*p_month, *p_year;
X	double	*p_day, jday;
X{
X	int	atmp, btmp, ctmp, dtmp, etmp, gtmp, ztmp;
X	double	ftmp;
X
X	ztmp = jday + 0.5;
X	ftmp = (jday + 0.5) - ztmp;
X	if (ztmp >= 2299161) {
X		gtmp = (ztmp - 1867216.25) / 36524.25;
X		ctmp = gtmp / 4;
X		atmp = ztmp + 1 + gtmp - ctmp;
X	}
X	else
X		atmp = ztmp;
X	btmp = atmp + 1524;
X	ctmp = (btmp - 122.1) / 365.25;
X	dtmp = 365.25 * ctmp;
X	etmp = ((btmp - dtmp) / 30.6001);
X	ztmp = 30.6001 * etmp;
X	*p_day = btmp - dtmp - ztmp + ftmp;
X	if (etmp > 13.5)
X		*p_month = etmp - 13;
X	else
X		*p_month = etmp - 1;
X	if (*p_month > 2.5)
X		*p_year = ctmp - 4716;
X	else
X		*p_year = ctmp - 4715;
X}
X
X/*
X * mdays_between_dates:
X * Compute number of mdays between two dates (exclusive: don't count the
X * days themselves) given day of week (0-6, O for Sunday),
X * two sets of day (1-31), month (1-12), year (1583-9999)
X */
Xmdays_between_dates(day_of_week, day1, month1, year1, day2, month2, year2)
X	int	day_of_week, month1, year1, month2, year2;
X	double	day1, day2;
X{
X	return wday(day_of_week, day2, month2, year2)
X		- wday(day_of_week, day1, month1, year1);
X}
X
X/*
X * years_date_is_mday:
X * Compute year(s) for which a given date is an m-day
X * given starting year, ending year,
X * day of week (0-6, 0 for Sunday), day, and month
X * algorithm said to be valid for 1 Mar 1900 to 28 Feb 2100.
X */
Xyears_date_is_mday(day_of_week, day, month, start_year, end_year, yearlist,
X	number_of_years)
X	int	day_of_week, end_year, month, *number_of_years, yearlist[],
X		start_year;
X	double	day;
X{
X	int		diff, index, year, tdow;
X	static int	augment[] = {6, 11, 6, 5}; 
X
X	*number_of_years = 0;
X	if (start_year > end_year) return -1;
X	for (year = start_year; year <= end_year; year++ ) {
X		tdow = get_day_of_week(day, month, year);
X		if (tdow == day_of_week) {
X			yearlist[(*number_of_years)++] = year;
X		}
X		if (*number_of_years == 2 || *number_of_years == 3) {
X			diff = yearlist[*number_of_years]
X				- yearlist[*number_of_years - 1];
X			if (diff == 5) {
X				year++;
X				index = 0;
X				break;
X			}
X			else if (diff == 11) {
X				year++;
X				index = 2;
X				break;
X			}
X		}
X	}
X	for ( ; year <= end_year; year++ ) {
X		yearlist[(*number_of_years + 1)] =
X			yearlist[*number_of_years] + augment[index++ % 4];
X		(*number_of_years)++;
X	}
X	return 0;
X}
X
X/*
X * weekdays_between_dates:
X * Compute weekdays between any two dates
X * given two sets of day (1-31), month (1-12), year (1901-2009)
X */
Xweekdays_between_dates(day1, month1, year1, day2, month2, year2)
X	int	month1, month2, year1, year2;
X	double	day1, day2;
X{
X	return wday2(day2, month2, year2) - wday2(day1, month1, year1);
X}
X
X/*
X * wday:
X * Compute wday for mdays_between_dates routine
X * given day of week, day, month, year
X */
Xwday(day_of_week, day, month, year)
X	int	day_of_week, month, year;
X	double	day;
X{
X	int	atmp, btmp, ctmp, dtmp;
X
X	atmp = dday(day, month, year) - day_of_week;
X	btmp = atmp / 7;
X	ctmp = atmp % 7;
X	dtmp = 0.11 * ctmp + 0.9;
X	return btmp + (0.5 * dtmp);
X}
X
X/*
X * wday2:
X * Compute wday2 for weekdays_between_dates routine
X * given day, month, year
X */
Xwday2(day, month, year)
X	int	month, year;
X	double	day;
X{
X	int	atmp, btmp, ctmp, dtmp;
X
X	atmp = dday(day, month, year);
X	btmp = atmp / 7;
X	ctmp = atmp % 7;
X	dtmp = 1.801 * ctmp;
X	return (5 * btmp) + (0.5 * dtmp);
X}
X
X/*
X * dday:
X * Compute dday for other routines
X * given day (1-31), month (1-12), year (1901-2009)
X */
Xdday(day, month, year)
X	int	month, year;
X	double	day;
X{
X	int	atmp, btmp, ctmp, dtmp, tmonth, tyear;
X
X	if (month > 2) {
X		tmonth = month + 1;
X		tyear = year;
X	}
X	else {
X		tmonth = month + 13;
X		tyear = year - 1;
X	}
X	atmp = tyear / 100;
X	btmp = 0.75 * (atmp - 7);
X	ctmp = 365.25 * tyear;
X	dtmp = 30.6001 * tmonth;
X	return (int) day - btmp + ctmp + dtmp;
X}
X
X/*
X * vernal_equinox:
X * Compute Julian day for Vernal (March) Equinox given year (1901-2009)
X */
Xdouble
Xvernal_equinox(year)
X	int	year;
X{
X	double	solstice_equinox_exact();
X
X	return solstice_equinox_exact(0, year);
X}
X
X/*
X * summer_solstice:
X * Compute Julian day for Summer Solstice (June) given year (1901-2009)
X */
Xdouble
Xsummer_solstice(year)
X	int	year;
X{
X	double	solstice_equinox_exact();
X
X	return solstice_equinox_exact(1, year);
X}
X
X/*
X * autumn_equinox:
X * Compute Julian day for Autumnal (September) Equinox given year (1901-2009)
X */
Xdouble
Xautumn_equinox(year)
X	int	year;
X{
X	double	solstice_equinox_exact();
X
X	return solstice_equinox_exact(2, year);
X}
X
X/*
X * winter_solstice:
X * Compute Julian day for Winter (December) Solstice given year (1901-2009)
X */
Xdouble
Xwinter_solstice(year)
X	int	year;
X{
X	double	day, jday;
X	int	month, nyear;
X	double	solstice_equinox_exact();
X
X	jday = solstice_equinox_exact(3, year);
X	gregorian_date(&day, &month, &nyear, jday);
X	if (nyear == year)
X		return jday;
X	else
X		return solstice_equinox_exact(3, (year + 1));
X}
X
X/*
X * solstice_equinox__exact:
X * Compute more precise date for Solstice/Equinox
X * given code (0-3, 0 for Vernal Equinox), year (1901-2009)
X */
Xdouble
Xsolstice_equinox_exact(code, year)
X	int	code, year;
X{
X	int	count;
X
X	double	corr, jday_app;
X	double	solstice_equinox_approx(), solstice_equinox_correction();
X
X	/* compute first approximation to Julian day */
X	jday_app = solstice_equinox_approx(code-1, year);
X	/* iteratively recompute corrected Julian day */
X	for(count = 0; count < 15; count++) {
X		corr = solstice_equinox_correction(jday_app, code);
X		jday_app += corr;
X		if (fabs(corr) < 0.00001)
X			break;
X	}
X	return jday_app;
X}
X
X/*
X * solstice_equinox_correction:
X * Compute correction for Solstice/Equinox Julian day
X * approximate Julian day, code (0-3, 0 for Vernal Equinox)
X */
Xdouble
Xsolstice_equinox_correction(jday, code)
X	int	code;
X	double	jday;
X{
X	double	apparent_longitude(), sin_degrees();
X
X	return(58.0 * sin_degrees((code * 90.0) - apparent_longitude(jday)));
X}
X
X/*
X * apparent_longitude:
X * Compute apparent longitude (true equinox) of Sun for
X * Solstice/Equinox given approximate Julian day
X */
Xdouble
Xapparent_longitude(jday)
X	double	jday;
X{
X	double	btmp, ctmp, dtmp, etmp, ftmp;
X	double	sin_degrees();
X
X	btmp = (jday - 2415020.0) / 36525.0;	/* time in Julian centuries: */
X						/* epoch 0.5 January 1900 */
X	ctmp = 279.69668 + (36000.76892 * btmp) /* geometric mean longitude */
X		+ (0.0003025 * btmp * btmp);	/* (mean equinox of the date) */
X	dtmp = 358.47583 + (35999.04975 * btmp)	/* mean anomaly of Sun */
X		+ (0.00015 * btmp * btmp)
X		+ (0.0000033 * btmp * btmp * btmp);
X	etmp = (1.919460 - (0.004789 * btmp)	/* Sun's eqn of the center */
X		- (0.000014 * btmp)) * sin_degrees(dtmp)
X		+ (0.020094 - (0.0001 * btmp)) * sin_degrees(2 * dtmp)
X		+ 0.000293 * sin_degrees(3 * dtmp);
X	ftmp = ctmp + etmp;			/* Sun's true longitude */
X	return ftmp - 0.00569			/* app. long. of Sun */
X		- 0.00479 * sin_degrees(259.18	/* (true equinox of the date) */
X		- (1934.142 * btmp));
X}
X
X/*
X * sin_degrees:
X * Compute sin for argument in degrees
X */
Xdouble
Xsin_degrees(degrees)
X#define	PI_CORR	0.01745329252				/* pi / 180 */
X	double	degrees;
X{
X	return sin(degrees * PI_CORR);
X}
X
X/*
X * solstice_equinox_approx:
X * Compute approximate date for Solstice/Equinox
X * given code (0-3, 0 for Vernal Equinox), year (1901-2009)
X */
Xdouble
Xsolstice_equinox_approx(code, year)
X	int	code, year;
X{
X	return (365.2422 * (year + (code / 4))) + 1721141.3;
X}
X
X/*
X * easter:
X * Return Julian date for Easter, given year (1901-2009)
X *
X * Offered in the book of Meeus, which cites:
X *
X * 1) Spencer Jones
X *    General Astronomy
X *    1922
X *    pg. 73-74
X *
X * 2) Journal of the British Astronomical Association
X *    Vol. 8
X *    Pg. 91
X *    Dec. 1977
X *    (which attributes method to Butcher's Ecclesiastical Calendar of 1876)
X *
X * Method valid for all dates in the Gregorian calendar
X * (from 15 October 1583 on)
X */
Xvoid
Xeaster_init(year)
X	int	year;
X{
X	double	day;
X	int	atmp, btmp, ctmp, dtmp, etmp, ftmp,
X		gtmp, htmp, itmp, ktmp, ltmp, mtmp;
X	int	month;
X
X	atmp = year % 19;
X	btmp = year / 100;
X	ctmp = year % 100;
X	dtmp = btmp / 4;
X	etmp = btmp % 4;
X	ftmp = (btmp + 8) / 25;
X	gtmp = (btmp - ftmp + 1) / 3;
X	htmp = ((19 * atmp) + btmp - dtmp - gtmp + 15) % 30;
X	itmp = ctmp / 4;
X	ktmp = ctmp % 4;
X	ltmp = (32 + (2 * etmp) + (2 * itmp) - htmp - ktmp) % 7;
X	mtmp = (atmp + (11 * htmp) + (22 * ltmp)) / 451;
X	month = (htmp + ltmp - (7 * mtmp) + 114) / 31;
X	day = ((htmp + ltmp - (7 * mtmp) + 114) % 31) + 1;
X	easterJD = julian_day(day, month, year);
X}
X
Xdouble
Xeaster(year)
X	int	year;
X{
X	return easterJD;
X}
X
X/*
X * first_sunday_advent:
X * Christian holidays: compute Julian day for First Sunday in Advent
X * (closest Sunday to St. Andrew's day, the last day in November)
X * given year (>1583)
X */
Xdouble
Xfirst_sunday_advent(year)
X	int	year;
X{
X	int	atmp;
X
X	atmp = get_day_of_week(30.0, 11, year);
X	if (atmp <= 3) {
X		return julian_day((30.0 - (double) atmp), 11, year);
X	}
X	else {
X		return julian_day(30.0, 11, year) + (7 - atmp);
X	}
X}
X
X/*
X * easter_offset:
X * Christian holidays: compute Julian day as offset from Easter
X * given year (>1583)
X */
Xdouble
Xeaster_offset(offset, year)
X	double	offset;
X	int	year;
X{
X	return easterJD + offset;
X}
X
X/*
X * septuagesima:
X * Christian holidays: compute Julian day for Septuagesima Sunday
X * (Third Sunday before Lent)
X * given year (>1583)
X */
Xdouble
Xseptuagesima(year)
X	int	year;
X{
X	return easter_offset(-63.0, year);
X}
X
X/*
X * sexagesima:
X * Christian holidays: compute Julian day for Sexagesima Sunday
X * (Second Sunday before Lent)
X * given year (>1583)
X */
Xdouble
Xsexagesima(year)
X	int	year;
X{
X	return easter_offset(-56.0, year);
X}
X
X/*
X * quinquagesima:
X * Christian holidays: compute Julian day for Quinquagesima (Shrove) Sunday
X * (Sunday before Lent begins on Ash Wednesday)
X * given year (>1583)
X */
Xdouble
Xquinquagesima(year)
X	int	year;
X{
X	return easter_offset(-49.0, year);
X}
X
X/*
X * shrove_monday:
X * Christian holidays: compute Julian day for Shrove Monday
X * (Two days before Lent begins on Ash Wednesday)
X * given year (>1583)
X */
Xdouble
Xshrove_monday(year)
X	int	year;
X{
X	return easter_offset(-48.0, year);
X}
X
X/*
X * shrove_tuesday:
X * Christian holidays: compute Julian day for Shrove Tuesday
X * (Day before Lent begins on Ash Wednesday; Mardi Gras)
X * given year (>1583)
X */
Xdouble
Xshrove_tuesday(year)
X	int	year;
X{
X	return easter_offset(-47.0, year);
X}
X
X/*
X * ash_wednesday:
X * Christian holidays: compute Julian day for Ash Wednesday
X * given year (>1583)
X */
Xdouble
Xash_wednesday(year)
X	int	year;
X{
X	return easter_offset(-46.0, year);
X}
X
X/*
X * first_sunday_lent:
X * Christian holidays: compute Julian day for First Sunday in Lent
X * given year (>1583)
X */
Xdouble
Xfirst_sunday_lent(year)
X	int	year;
X{
X	return easter_offset(-42.0, year);
X}
X
X/*
X * second_sunday_lent:
X * Christian holidays: compute Julian day for Second Sunday in Lent
X * given year (>1583)
X */
Xdouble
Xsecond_sunday_lent(year)
X	int	year;
X{
X	return easter_offset(-35.0, year);
X}
X
X/*
X * third_sunday_lent:
X * Christian holidays: compute Julian day for Third Sunday in Lent
X * given year (>1583)
X */
Xdouble
Xthird_sunday_lent(year)
X	int	year;
X{
X	return easter_offset(-28.0, year);
X}
X
X/*
X * fourth_sunday_lent:
X * Christian holidays: compute Julian day for Fourth Sunday in Lent
X * given year (>1583)
X */
Xdouble
Xfourth_sunday_lent(year)
X	int	year;
X{
X	return easter_offset(-21.0, year);
X}
X
X/*
X * passion_sunday:
X * Christian holidays: compute Julian day for Passion Sunday
X * (Second Sunday before Easter)
X * given year (>1583)
X */
Xdouble
Xpassion_sunday(year)
X	int	year;
X{
X	return easter_offset(-14.0, year);
X}
X
X/*
X * palm_sunday:
X * Christian holidays: compute Julian day for Palm Sunday
X * (Sunday before Easter)
X * given year (>1583)
X */
Xdouble
Xpalm_sunday(year)
X	int	year;
X{
X	return easter_offset(-7.0, year);
X}
X
X/*
X * maundy_thursday:
X * Christian holidays: compute Julian day for Maundy Thursday
X * (Three days prior to Easter)
X * given year (>1583)
X */
Xdouble
Xmaundy_thursday(year)
X	int	year;
X{
X	return easter_offset(-3.0, year);
X}
X
X/*
X * good_friday:
X * Christian holidays: compute Julian day for Good Friday
X * (Two days prior to Easter)
X * given year (>1583)
X */
Xdouble
Xgood_friday(year)
X	int	year;
X{
X	return easter_offset(-2.0, year);
X}
X
X/*
X * easter_monday:
X * Christian holidays: compute Julian day for Easter Monday (Canada)
X * given year (>1583)
X */
Xdouble
Xeaster_monday(year)
X	int	year;
X{
X	return easter_offset(1.0, year);
X}
X
X/*
X * rogation_sunday:
X * Christian holidays: compute Julian day for Rogation Sunday
X * (Rogation is the period of three days prior to Ascension Day; strictly
X * speaking, this is the period Mon-Wed)
X * given year (>1583)
X */
Xdouble
Xrogation_sunday(year)
X	int	year;
X{
X	return easter_offset(35.0, year);
X}
X
X/*
X * ascension_day:
X * Christian holidays: compute Julian day for Ascension Day
X * (Holy Thursday; fortieth day after Easter, inclusive)
X * given year (>1583)
X */
Xdouble
Xascension_day(year)
X	int	year;
X{
X	return easter_offset(39.0, year);
X}
X
X/*
X * whitsunday:
X * Christian holidays: compute Julian day for Whitsunday (Pentecost)
X * (Seventh Sunday after Easter)
X * given year (>1583)
X */
Xdouble
Xwhitsunday(year)
X	int	year;
X{
X	return easter_offset(49.0, year);
X}
X
X/*
X * trinity_sunday:
X * Christian holidays: compute Julian day for Trinity Sunday
X * (Eighth Sunday after Easter)
X * given year (>1583)
X */
Xdouble
Xtrinity_sunday(year)
X	int	year;
X{
X	return easter_offset(56.0, year);
X}
X
X/*
X * corpus_christi:
X * Christian holidays: compute Julian day for Corpus Christi
X * (First Thursday after Trinity Sunday)
X * given year (>1583)
X */
Xdouble
Xcorpus_christi(year)
X	int	year;
X{
X	return easter_offset(60.0, year);
X}
X
X/*
X * passover:
X * Jewish holidays: compute Julian day of Pesach (first day of Passover)
X * and establish the Gregorian day of month and month, and Jewish year,
X * given Julian year (>1583)
X * This formula, due to Karl Friedrich Gauss (1777-1855) is described in
X * excruciating detail in the book by Schocken P. 51-61).  Note that it
X * computes the Julian date, which has to be corrected to a Gregorian date,
X * and that it exhibits the eccentricity of always computing the day
X * relative to March, so that April 2 appears as March 33, which is also
X * corrected below.
X *
X * Floating point implementation by R.P.C. Rodgers; integer implementation
X * (for faster calculation) by Amos Shapir (amos@nsc.com).
X */
Xvoid
Xpassover_init(year)
X	int	year;
X{
X	int	etmp, p_day;
X	int	atmp, btmp, ctmp, day_of_week, dtmp, ftmp, gtmp;
X	int	p_month;
X
X	atmp = year + 3760;
X	passoverJY = atmp;
X	btmp = (12 * atmp + 17) % 19;
X	ctmp = atmp % 4;
X	etmp = (765433 * btmp) - (1565 * atmp)
X		+ (ctmp * 123120) + 15781075;
X	dtmp = etmp / 492480;
X	etmp %= 492480;
X		/* day_of_week is not to be confused with the
X		 value returned by the day_of_week routine; here, Sunday = 1 */
X	day_of_week = ((3 * atmp) + (5 * ctmp) + dtmp + 5) % 7;
X	if (day_of_week == 0 && btmp > 11 && etmp >= 442111)
X		p_day = dtmp + 1;
X	else if (day_of_week == 1 && btmp > 6 && etmp >= 311676)
X		p_day = dtmp + 2;
X	else if (day_of_week == 2 || day_of_week == 4 || day_of_week ==6)
X		p_day = dtmp + 1;
X	else {
X		p_day = dtmp;
X	}
X	ftmp = year / 100;		/* Correct to Gregorian date */
X	gtmp = ((3 * ftmp) - 5) / 4;
X	p_day += gtmp;
X	if (p_day > 31) {		/* Correct for March days > 31 */
X		p_day -= 31;
X		p_month = 4;
X		}
X	else
X		p_month = 3;
X	passoverJD = julian_day((double)p_day, p_month, year);
X}
X
Xdouble
Xpassover(year, jyear)
X	int year, *jyear;
X{
X	*jyear = passoverJY;
X	return passoverJD;
X}
X
X/*
X * passover_offset:
X * Jewish holidays: compute Julian day as offset from Passover
X * given year (>1583)
X */
Xdouble
Xpassover_offset(offset, year, jyear)
X	double	offset;
X	int	*jyear, year;
X{
X	*jyear = passoverJY;
X	return passoverJD + offset;
X}
X
X/*
X * purim:
X * Jewish holidays: compute Julian day and Jewish year for Purim (Feast of Lots)
X * given year (>1583)
X */
Xdouble
Xpurim(year, jyear)
X	int	*jyear, year;
X{
X	return passover_offset(-30.0, year, jyear);
X}
X
X/*
X * shavuot:
X * Jewish holidays: compute Julian day and Jewish year for First day of Shavuot
X * given year (>1583)
X */
Xdouble
Xshavuot(year, jyear)
X	int	*jyear, year;
X{
X	return passover_offset(50.0, year, jyear);
X}
X
X/*
X * rosh_hashanah:
X * Jewish holidays: compute Julian day and Jewish year for first day of
X * Rosh Hashanah (New Year) given year (>1583)
X */
Xdouble
Xrosh_hashanah(year, jyear)
X	int	*jyear, year;
X{
X	double	atmp;
X	atmp = passover_offset(163.0, year, jyear);
X	(*jyear)++;
X	return atmp;
X}
X
X/*
X * yom_kippur:
X * Jewish holidays: compute Julian day and Jewish year for Yom Kippur
X * given year (>1583)
X */
Xdouble
Xyom_kippur(year, jyear)
X	int	*jyear, year;
X{
X	double	atmp;
X	atmp = passover_offset(172.0, year, jyear);
X	(*jyear)++;
X	return atmp;
X}
X
X/*
X * sukkot:
X * Jewish holidays: compute Julian day and Jewish year for
X * First day of Sukkot (9 days) given year (>1583)
X */
Xdouble
Xsukkot(year, jyear)
X	int	*jyear, year;
X{
X	double	atmp;
X	atmp = passover_offset(177.0, year, jyear);
X	(*jyear)++;
X	return atmp;
X}
X
X/*
X * simchat_torah:
X * Jewish holidays: compute Julian day and Jewish year for Simchat Torah
X * (in Diapsora) given year (>1583)
X */
Xdouble
Xsimchat_torah(year, jyear)
X	int	*jyear, year;
X{
X	double	atmp;
X	atmp = passover_offset(185.0, year, jyear);
X	(*jyear)++;
X	return atmp;
X}
X
X/*
X * chanukah:
X * Jewish holidays: compute Julian day and Jewish year for
X * first day of Chanukah (8 days) given year (>1583)
X */
Xdouble
Xchanukah(year, jyear)
X	int	*jyear, year;
X{
X	double	atmp, ptmp;
X	int	btmp, ytmp;
X
X	atmp = passover(year, jyear);
X	/* we need top compute passover for next year, so
X	 * save current info and restore when done
X	 */
X	ptmp = passoverJD;
X	ytmp = passoverJY;
X	passover_init(year + 1);
X	btmp = passoverJD - atmp;
X	passoverJD = ptmp;
X	passoverJY = ytmp;
X	(*jyear)++;
X	if (btmp == 355 || btmp == 385)
X		return atmp + 247.0;
X	else
X		return atmp + 246.0;
X}
X
X/*
X * islamic_date:
X * Islamic holidays: compute Gregorian date(s) and Islamic year for any
X * Islamic day, given ISLAMIC day (1-30), ISLAMIC month(1-12),
X * and GREGORIAN year (>1583)
X * This is complicated by the fact that a given Islamic date can appear as
X * often as twice within the same Gregorian year.
X */
Xislamic_date(
X	mday, mmonth, number_of_days, day1, month1, day2, month2, year, myear1,
X	myear2)
X	double	*day1, *day2, mday;
X	int	mmonth, *month1, *month2, *myear1, *myear2,
X		*number_of_days, year;
X{
X	double	day;
X	int	count, month, nyear;
X	double	islamic_to_julian();
X
X	*myear1 = year - 621;		/* approx. >= Muslim year */
X	nyear = year - 1;
X	for (count = 0; nyear != year && count <= 100; count++) {
X		gregorian_date(&day, &month, &nyear,
X			islamic_to_julian(mday, mmonth, *myear1));
X		*myear1 = *myear1 + (year - nyear);
X	}
X	if (nyear == year) {
X		*day1 = day;
X		*month1 = month;
X		/*
X		 * See if there is a second occurrence in same Gregorian year
X		 */
X		gregorian_date(&day, &month, &nyear,
X			islamic_to_julian(mday, mmonth, (*myear1 + 1)));
X		if (nyear == year) {
X			*day2 = day;
X			*month2 = month;
X			*number_of_days = 2;
X			*myear2 = *myear1 + 1;
X		}
X		else {
X			*number_of_days = 1;
X			gregorian_date(&day, &month, &nyear,
X				islamic_to_julian(mday, mmonth, (*myear1 - 1)));
X			if (nyear == year) {
X				*day2 = day;
X				*month2 = month;
X				*number_of_days = 2;
X				*myear2 = *myear1 + 1;
X			}
X		}
X	}
X/*	else return -1; */
X	return 0;
X}
X
X/*
X * islamic_to_julian:
X * Islamic holidays: compute Julian day for any Islamic day,
X * given ISLAMIC day (1-30), ISLAMIC month(1-12), and ISLAMIC year (>962)
X * Formula from Schocken (p. 66)
X */
Xdouble
Xislamic_to_julian(mday, mmonth, myear)
X	double	mday;
X	int	mmonth, myear;
X{
X	double	etmp, ftmp, jday;
X	int	atmp, btmp, ctmp, dtmp, nyear;
X	double	corrected_julian_day();
X
X	nyear = myear + 621;		/* approx. Julian year */
X	atmp = ((19 * myear) - 4) % 30;
X	btmp = nyear % 4;
X	ctmp = (mmonth - 1) / 2;
X	dtmp = (mmonth - 1) % 2;
X	etmp = mday + (59.0 * ctmp) + (30.0 * dtmp) + (atmp / 30.0)
X	 	+ (btmp / 4.0) - (10.8833333 * myear) + 146.8833333;
X	if (etmp < 0.0) {
X		ftmp = (4.0 * fabs(etmp)) / 1461.0;
X		atmp = ftmp;
X		dtmp = (4.0 * fabs(etmp));
X		dtmp = dtmp % 1461;
X		nyear -= (atmp + 1);
X		ctmp = nyear % 4;
X		jday = julian_day(1.0, 3, nyear)
X			+ (((1461.0 - dtmp) + ctmp - btmp) / 4.0)
X			- 1.0;
X		return corrected_julian_day(jday);
X	}
X	jday = julian_day(1.0, 3, nyear) + etmp - 1.0;
X	return corrected_julian_day(jday);
X}
X
X/*
X * islamic_new_year:
X * Islamic holidays: compute Julian date(s) and Islamic year(s)
X * for Islamic New Year given JULIAN year (>1583)
X * (note: due to the length of the Islamic year (355 d), there can be portions
X * of as many as two Islamic New Years within a given Gregorian year; for
X * example, according to the algorithm below, the Islamic New Year occured
X * twice in 1975: Wednesday 1 January, Sunday 21 December)
X *
X * Algorithm: Schocken, page 66, which agrees with dates I have obtained for
X * the (Gregorian) years 1962-2000.  Schocken outlines a Muslim calendar
X * consisting of 12 months which are alternately 30 and 29 days in length
X * (the first month, Muharram, is 30 days in length).  In a 30-year cycle,
X * there are 11 leap years in which a 30th day is added to the final month
X * of the year.  See full details below.
X *
X * According to Dr. Omar Afzal of Cornell University ((607)255-5118,
X * 277-6707; Chairman of the Committee for Crescent Observation;
X * irfan@mvax.ee.cornell.edu), this is an antiquated system which has been
X * in use for some 400 years, but today the Muslim calendar follows a more
X * strictly lunar basis.  I wish to acknowledge the Pakistani Consular
X * Office of San Francisco (415)788-0677, who referred me to Dr. Muzammil
X * Siddiqui of the Orange County Islamic Center, (714)531-1722, who in turn
X * referred me to to Dr. Afzal.  I thank Dr. Afzal for his patient and lucid
X * explanations of the Islamic calendar, and for providing printed matter and
X * tables of dates to assist me.  Among the sources he provided:
X *
X * %A U. V. Tsybulsky
X * %B Calendar of Middle Eastern Countries
X * %I Nauka Publishing House
X * %C Moscow
X * %L English
X * %D 1979
X *
X * which provides a scholarly discussion of calendrical conventions in various
X * Muslim countries, as well as simple formulas for conversion between
X * Gregorian and Islamic dates.  It also includes translations of tables which
X * originally appeared in:
X *
X * %A F. R. Unat
X * %B Hicri Tarihleri
X * %I Turktarih Kurumu Basimevi
X * %C Ankara
X * %L Turkish
X * %D 1959
X *
X * Additional tabular material is available in:
X *
X * %A G. S. P. Freeman-Grenville
X * %B The Muslim and Christian Calendars
X * %I Oxford University Press
X * %C London
X * %D 1963
X *
X * The Islamic calendar is also known as the Hijri calendar, and dates often
X * have "A.H." or "a.h." appended to them to indicate "Anno Hijri."  A
X * listing of the months and their lengths (in the old scheme):
X *
X *    Month Name     Days         Days to add to 1 Muharram to get 1st of month
X * 1  Muharram        30          0
X * 2  Safar           29         30
X * 3  Rabi' al-Awwal  30         59
X * 4  Rabi' ath-Thani 29         89
X * 5  Jumada al-Ula   30        118
X * 6  Jumada al-Akhir 29        148
X * 7  Rajab           30        177
X * 8  Sha'ban         29        207
X * 9  Ramadan         30        236
X * 10 Shawwal         29        266
X * 11 Dhul-Qa'da      30        295
X * 12 Dhul-Hijja      29 (30)   325
X *
X * In the old scheme, used here for simplicity, adherence to this set of rules
X * led to a gradual lag of the month behind the actual crescent moon.  Thus,
X * a leap day was appended to the final month in each of 11 years out of every
X * 30 year cycle: (2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29).  If the Hijra year
X * is divided by 30, and the remainder is equal to one of these numbers, it is
X * a leap year.
X *
X * The Islamic day begins after sunset, and the beginning of the month is tied
X * to the first VISIBLE appearance of the crescent moon, which often lags behind
X * the astronomical new moon.  Also, the crescent was sometimes computed
X * according to Mecca time.  There are numerous methods for defining the date
X * of the crescent moon (and hence calendar dates) among the various Muslim
X * regions of the world.  Given these uncertainties, the dates computed here are
X * likely to be accurate to only +/- 2 days.
X *
X * Any errors in this code are my own fault, and
X * not intended to offend any members of the Islamic faith.
X */
Xislamic_new_year(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	double	day1, day2;
X	int	month1, month2;
X
X	if (islamic_date(1.0, 1, number_of_dates, &day1, &month1, &day2,
X		&month2, year, myear1, myear2) < 0) return -1;
X	*date1 = julian_day(day1, month1, year);
X	if (*number_of_dates == 2) *date2 = julian_day(day2, month2, year);
X	return 0;
X}
X
X/*
X * islamic_offset:
X * Islamic holidays: compute Julian day(s) for an Islamic date as an offset
X * from the Islamic New Year, given (Gregorian) year
X */
Xislamic_offset(offset, year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2, offset;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	double	day, tdate1, tdate2;
X	int	month, tyear1, tyear2;
X
X	(void) islamic_new_year(year, number_of_dates, date1, date2,
X		myear1, myear2);
X	if (*number_of_dates == 2) {
X		tdate2 = *date2 + offset;
X		gregorian_date(&day, &month, &tyear2, tdate2);
X		if (tyear2 > year) {
X			tdate2 = *date1 + offset;
X			(void) islamic_new_year((year - 1), number_of_dates,
X				date1, date2, myear1, myear2);
X			tdate1 = *date1 + offset;
X			gregorian_date(&day, &month, &tyear1, tdate1);
X			if (tyear1 == year) {
X				*date1 = tdate1;
X				*date2 = tdate2;
X				*number_of_dates = 2;
X				*myear2 = *myear1 + 1;
X			}
X			else {
X				*date1 = tdate2;
X				*number_of_dates = 1;
X				*myear1 = *myear1 + 1;
X			}
X		}
X		else {
X			*date1 += offset;
X			*date2 = tdate2;
X		}
X	}
X	else {
X		tdate2 = *date1 + offset;
X		gregorian_date(&day, &month, &tyear2, tdate2);
X		if (tyear2 > year) {
X			(void) islamic_new_year((year - 1), number_of_dates,
X				date1, date2, myear1, myear2);
X			if (*number_of_dates == 2) {
X				*date1 = *date2 + offset;
X				*number_of_dates = 1;
X				*myear1 = *myear2;
X			}
X			else {
X				*date1 = *date1 + offset;
X			}
X		}
X		else {
X			(void) islamic_new_year((year - 1), number_of_dates,
X				date1, date2, myear1, myear2);
X			if (*number_of_dates == 2) {
X				tdate1 = *date2 + offset;
X				*myear1 = *myear2;
X			}
X			else {
X				tdate1 = *date1 + offset;
X			}
X			gregorian_date(&day, &month, &tyear1, tdate1);
X			if (tyear1 == year) {
X				*date1 = tdate1;
X				*date2 = tdate2;
X				*number_of_dates = 2;
X				*myear2 = *myear1 + 1;
X			}
X			else {
X				*date1 = tdate2;
X				*myear1 = *myear1 + 1;
X				*number_of_dates = 1;
X			}
X		}
X	}
X}
X
X/*
X * muharram_9:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Muharram 9 (Day of fasting) given year (>1583)
X */
Xmuharram_9(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		8.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * muharram_10:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Muharram 10 (Day of deliverance of Moses from the Pharoah; for Shia Islam,
X * martyrdom of Husain) given year (>1583)
X */
Xmuharram_10(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		9.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * muharram_16:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Muharram 16 (Imamat Day; Ismaili Khoja) given year (>1583)
X */
Xmuharram_16(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		15.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * eid_i_milad_un_nabi:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Rabi I 12 (Eid-i-Milad-un-Nabi: The Prophet's Birthday) given year (>1583)
X */
Xeid_i_milad_un_nabi(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		70.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * jumada_al_akhir_23:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Jumada al-Akhir 23 (Birth of Agha Khan IV, Ismaili) given year (>1583)
X */
Xjumada_al_akhir_23(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		170.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * shab_e_miraj:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Rajab 27 (Shab-e-Mi'raj: The Prophet's Ascension) given year (>1583)
X */
Xshab_e_miraj(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		203.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * shab_e_barat:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Shaban 15 (Shab-e-Bara't: Night, followed by day of fasting) given year (>1583)
X */
Xshab_e_barat(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		221.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * ramadan:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Ramadan 1 (Fasting month begins) given year (>1583)
X */
Xramadan(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		236.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * shab_e_qadr:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Ramadan 27 (Shab-e Qadr: Night vigil) given year (>1583)
X */
Xshab_e_qadr(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		262.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * eid_al_fitr:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Shawwal 1 (Eid-al-Fitr: Day of Feast) given year (>1583)
X */
Xeid_al_fitr(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		266.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * dhul_hijja_9:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Dhul-Hijj 9 (Day of Pilgrimage at Arafat, Mecca) given year (>1583)
X */
Xdhul_hijja_9(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		333.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * eid_al_adha:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Dhul-Hijj 10 (Eid-al-Adha: Day of Abraham's Sacrifice) given year (>1583)
X */
Xeid_al_adha(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		334.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * ghadir:
X * Islamic holidays: compute Julian day(s) and Islamic year(s) for
X * Dhul-Hijj 18 (Ghadir: Ali's Nomination) given year (>1583)
X */
Xghadir(year, number_of_dates, date1, date2, myear1, myear2)
X	double	*date1, *date2;
X	int	*number_of_dates, *myear1, *myear2, year;
X{
X	islamic_offset(
X		342.0, year, number_of_dates, date1, date2, myear1, myear2);
X}
X
X/*
X * print_islamic_string:
X * Print formatted date string(s) of form:
X *    Monday 1 August 1988 (Islamic year 1409)
X * given string labelling date, (Gregorian) year of event, and function which
X * takes (Gregorian) year as an argument and produces: the (integer) number of
X * Gregorian dates (1 or 2), the first and second (Julian) days, and the first
X * and second Islamic years.
X */
Xprint_islamic_string(string, year, func)
X	char	*string;
X	int	year;
X	int	(*func) ();
X{
X
X	char	*date;
X	double	date1, date2, day, holiday;
X	int	month, myear1, myear2, number_of_dates;
X	char	*date_string();
X
X	holiday = (*func) (
X		year, &number_of_dates, &date1, &date2, &myear1, &myear2);
X	if (holiday < 0)
X		(void) printf("Can not determine requested date\n");
X	else {
X		(void) printf("%s (%d) Julian day: %f\n", string, year, date1);
X		gregorian_date(&day, &month, &year, date1);
X		date = date_string(get_day_of_week(day, month, year),
X			day, month, year);
X		(void) printf("%s (%d): %s", string, year, date);
X		(void) printf(" (Islamic year %d)\n", myear1);
X		if (number_of_dates == 2) {
X			(void) printf(
X				"%s (%d) Julian day: %f\n", string, year,
X				date2);
X			gregorian_date(&day, &month, &year, date2);
X			date = date_string(get_day_of_week(day, month, year),
X				day, month, year);
X			(void) printf("%s (%d): %s", string, year, date);
X			(void) printf(" (Islamic year %d)\n",
X				myear2);
X		}
X	}
X}
X
X/*
X * print_date_and_time_string:
X * Print formatted date/time string of form: 10:42 Thursday 8 December 1988
X * given string labelling date, year of event, and function which takes year
X * as an argument and produces Julian day, 
X */
Xprint_date_and_time_string(string, year, func)
X	char	*string;
X	int	year;
X	double	(*func)();
X{
X	char	*date;
X	double	btmp, ctmp, day, holiday;
X	int	atmp, hour, min, month;
X	char	*date_time_string();
X
X	holiday = (*func) (year);
X	(void) printf("%s (%d) Julian day: %f\n", string, year, holiday);
X	gregorian_date(&day, &month, &year, holiday);
X	atmp = day;
X	btmp = day - atmp;
X	hour = btmp * 24.0;
X	ctmp = (btmp - (hour / 24.0)) * 1440.0;
X	min = ctmp;
X	date = date_time_string(hour, min, get_day_of_week(day, month, year),
X		day, month, year);
X	(void) printf("%s (%d): %s\n", string, year, date);
X}
X
X/*
X * print_date_string:
X * Print formatted date string of form: Thursday 8 December 1988
X * given string labelling date, year of event, and function which takes year
X * as an argument and produces Julian day. 
X */
Xprint_date_string(string, year, func)
X	char	*string;
X	int	year;
X	double	(*func) ();
X{
X	char	*date;
X	double	day, holiday;
X	int	month;
X	char	*date_string();
X
X	holiday = (*func) (year);
X	(void) printf("%s (%d) Julian day: %f\n", string, year, holiday);
X	gregorian_date(&day, &month, &year, holiday);
X	date = date_string(get_day_of_week(day, month, year), day, month, year);
X	(void) printf("%s (%d): %s\n", string, year, date);
X}
X
X/*
X * print_jewish_string:
X * Print formatted date string of form: Thursday 8 December 1988 (NYEAR)
X * given string labelling date, year of event, and function which takes year
X * as an argument, sets the value of a non-Gregorian year (NYEAR), and produces
X * the Julian day.
X */
Xprint_jewish_string(string, year, func)
X	char	*string;
X	int	year;
X	double	(*func) ();
X{
X	char	*date;
X	double	day, holiday;
X	int	month, nyear;
X	char	*date_string();
X
X	holiday = (*func) (year, &nyear);
X	(void) printf("%s (%d) Julian day: %f\n", string, year, holiday);
X	gregorian_date(&day, &month, &year, holiday);
X	date = date_string_2(get_day_of_week(day, month, year), day, month,
X		year, nyear);
X	(void) printf("%s (%d): %s\n", string, year, date);
X}
X
X/*
X * extract time of day from Julian day
X */
Xchar *
Xjulian_time(jday)
Xdouble jday;
X{
X	double	h1, floor();
X	int	hours, minutes;
X
X	jday += 0.5;  /* Julian day starts at noon GMT */
X	h1 = (jday - floor(jday)) * 24.; /* number of hours & frac of hours */
X	hours = (int) floor(h1);
X	minutes = (int) ((h1 - (double) hours) * 60.);
X	sprintf(timebuf, " at %d:%02d", hours, minutes);
X	return(timebuf);
X}
X
X/*
X * End of code
X */
X#endif	/* NO_HOLIDAYS */
END_OF_FILE
if test 44896 -ne `wc -c <'datelib.c'`; then
    echo shar: \"'datelib.c'\" unpacked with wrong size!
fi
# end of 'datelib.c'
fi
echo shar: End of archive 2 \(of 23\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 23 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.