Subject: Re: Need a MAC Jewish Calendar Program 
Distribution: world
Organization: Solvfield Ltd.
Reply-To: raph@panache.demon.co.uk
X-Mailer: Simple NEWS 1.90 (ka9q DIS 1.19)
Date: Mon, 25 Jan 1993 01:24:17 +0000

Here is the source of calendrical functions that will, amongst other things,
calculate the Jewish calendar. They ahve been tested on both SunOS and MSDOS.

The following functions are from Calendrical Calculations by N
Dershowitz and EM Reingold, Software Practice and Experience vol 20
(Sept 1990) No.  9 pp 899-928

The code is actually C, although it uses C++ style // comments.
--------------
Raphael Mankin			Nil taurus excretum

----------------- Cut here -------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -d ./tmp`
then
  mkdir ./tmp
  echo "mkdir ./tmp"
fi
if `test ! -s ./tmp/ZELLER.H`
then
echo "writing ./tmp/ZELLER.H"
cat > ./tmp/ZELLER.H << '\Rogue\Monster\'
#define UK

#define SUNDAY	0
#define	MONDAY	1
#define	TUESDAY	2
#define	WEDNESDAY	3
#define	THURSDAY	4
#define	FRIDAY	5
#define	SATURDAY	6
#define	FIRST	1
#define	SECOND	2
#define	THIRD	3
#define	FOURTH	4
#define	FIFTH	5
#define	LAST	-1

#define	UNIX_EPOCH	719163L		// 1 Jan 1970 CE
#define	DOS_EPOCH	722815L		// 1 Jan 1980 CE
#define	HEBREW_EPOCH	-1373429L	// 1 Tishri 1 AM

#include <time.h>
#include <stream.hpp>
#include <stdlib.h>
#include <assert.h>
int	Julianday(int day, int month, int year);
extern const char *monthName[] ;
extern const char *dayName[];
const char	*DayOfWeek(int day, int month, int year);
int	lastDayOfGregorianMonth(int month, int year);
long	absoluteFromGregorian(int day, int month, int year);
void	gregorianFromAbsolute(long days, int& day, int& month, int& year);
long	KdayOnOrBefore(long days, int dow);
long	NthKday(int n, int k, int month, int year);
long	dstStart(int year);
long	dstEnd(int year);
long	easter(int year);
int	hebrewLeapYear(int year);
int	lastMonthOfHebrewYear(int year);
long	hebrewCalendarElapsedDays(int year);
int	daysInHebrewYear(int year);
int	longHeshvanYear(int year);
int	shortKislevYear(int year);
int	lastDayOfHebrewMonth(int month, int year);
long	absoluteFromHebrew(int day, int month, int year);
void	hebrewFromAbsolute(long days, int& day, int& month, int& year);
long	roshHashana(int gregorianYear);
long	yomKippur(int gregorianYear);
long	succot(int gregorianYear);
long	pesach(int gregorianYear);
long	shavuot(int gregorianYear);
long	hanukka(int gregorianYear);
long	purim(int gregorianYear);
long	hebrewBirthday(int day, int month, int year, int gregorianYear);

\Rogue\Monster\
else
  echo "will not over write ./tmp/ZELLER.H"
fi
if `test ! -s ./tmp/ZELLER.CPP`
then
echo "writing ./tmp/ZELLER.CPP"
cat > ./tmp/ZELLER.CPP << '\Rogue\Monster\'
/*		ZELLER.C

These functions were written by Raphael Mankin (raph@panache.demon.co.uk)

Zeller was a mathematician and stage magician who did calendrical calculations
in his head as a stage trick.

*/
#include "zeller.h"

// Returns the day number within the year. Jan 1 is day 1.
int Julianday(int day, int month, int year)
{	int	daynumber;

	if (month <= 2) {
	    daynumber	= month*31 +day - 31;
	} else {
	    month -= 2;
	    daynumber	= (int)(month*30.59) +day + 29;
	    if (year%400==0 || (year%4 == 0 && year%100 !=0))
		daynumber++;
	}
	return daynumber;
}

// Effectively this is Zeller's congruence for calculating the
// day of the week from the date. Only valid for Gregorian dates,
// i.e. from 14 Sept 1752 in Britain, from other dates in various other
// European countries.
// The original Zeller's congruence is (2.6*month-0.2), but some
// computers require (2.6*month-0.1) to outwit their floating point
// arithmetic. There are all sorts other nearby values that also work.
// NB Internally, March is month 1, January is month 11

const char *monthName[] = {
	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
const char *dayName[] = {
	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
const char	*DayOfWeek(int day, int month, int year)
{
	month -= 2;			// March is month 1
	if (month <= 0) {		// February is month 12
		month+= 12;
		year--;
	}

	// First get the relative day of week of the first of the month.
	// The multiplier is a magic cookie that happens to
	// give us a straight line approximation to the number of days
	// in a month (modulo 7).
	int dnum = (int)(month*2.59);

	// Convert this to an absolute day by adding the day-of-month
	// and the year offset.
	int dow = (dnum + day + year + year/4 + year/400 - year/100)%7;
	return dayName[dow];
}

//The following functions are from Calendrical Calculations by N
//Dershowitz and EM Reingold, Software Practice and Experience vol 20
//(Sept 1990) No.  9 pp 899-928

// Absolute dates are the number of days since 1 Jan 1 AD (Gregorian),
// which is taken as day 1. Fortunately this is a Monday, so it we can
// continue to assume Sunday is day-of-week 0, Monday is day-of-week 1
// etc.

// There are 13 months in this list so that gregorianFromAbsolute()
// can wrap round 1 extra month in safety.
static int daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31};
int lastDayOfGregorianMonth(int month, int year)
{
	assert(month >= 1);
	assert(month <= 13);	// Yes, I do mean 13
	if (month == 2 &&
	    ((year%4 == 0 && year %100 != 0) || year%400==0))
		return 29;
	else
		return daysInMonth[month-1];
}

long	absoluteFromGregorian(int day, int month, int year)
{	long	days;
#if 0
	days	= 365L * (year-1) 
			+ (year-1)/4
			- (year-1)/100
			+ (year-1)/400
			+ day;
	for (int m=1; m < month; m++)
	    days	+= lastDayOfGregorianMonth(m, year);
#else	
    /*
	Use the equivalent of Zeller's congruence. The year begins in
	March, after any possible leap day. The '+31+28' offset below
	is to compensate for the January and February of year 1 which
	get pushed back into year 0.
    */
	month	-= 2;
	if (month <= 0) {
	    month	+= 12;
	    year--;
	}
	days	= 365L*(year-1) +year/4 -year/100 +year/400 +day +31 +28
			+ (int)(month*30.58-29.95);
#endif

	return days;
}

void	gregorianFromAbsolute(long days, int& day, int& month, int& year)
{	int	t = 0;

	for (year = days/366;
		absoluteFromGregorian(1, 1, year+1) <= days;
		year++);

	t	= 0;
	for (int m	= 1;
	    absoluteFromGregorian(lastDayOfGregorianMonth(m, year), m, year) < days;
	    m++)
	    t++;
	month	= 1+ t;

	day	= days - absoluteFromGregorian(1, month, year) + 1;
}
	
//	dow=0 for Sunday, 1 for Monday, ...
long	KdayOnOrBefore(long days, int dow)
{	return days - (days-dow)%7;	}

// Absolute date of the Nth K-day in month/year of the Gregorian calendar.
// If n is negative, we count from the end of the month, e.g. if n == -1
// and k == 0 we find the last Sunday in the month
long NthKday(int n, int k, int month, int year)
{
	if (n > 0) {
	    return
	    KdayOnOrBefore(absoluteFromGregorian(7, month, year), k)+
	    7* (n-1);
	} else {
	    return
	    KdayOnOrBefore(absoluteFromGregorian(lastDayOfGregorianMonth(month, year), month, year), k)
	    + 7 * (n+1);
	}
}

#ifdef USA
// Summer time in the USA runs from the first Sunday in April to the
// last Sunday in October
long	dstStart(int year)
{	return NthKday(FIRST, SUNDAY, 4, year);	}
long	dstEnd(int year)
{	return NthKday(LAST, SUNDAY, 10, year);		}
#endif
#ifdef UK
// Summer time in Britain runs from the last Sunday in March to the
// last (4th ?) Sunday in October. (2am GMT/3am BST).
long	dstStart(int year)
{	return NthKday(LAST, SUNDAY, 3, year);	}
long	dstEnd(int year)
{	return NthKday(FOURTH, SUNDAY, 10, year);		}
#endif

//	Modern calculation of Easter
long	easter(int year)
{	int	century	= 1 + year/100;
	int shiftedEpact= (14 + 11*(year%19)	// Age of moon on 5 April
			- (3*century)/4		// Correction for century
			+ (5+8*century)/25	// Corect for Metonic error
			+ 30*century) % 30;
	int adjustedEpact	= (shiftedEpact==0 ||
				    (shiftedEpact==1 && 10 < year%19))
				    ? 1 +shiftedEpact : shiftedEpact;
	long	paschalMoon	= absoluteFromGregorian(19, 4, year)
					- adjustedEpact;
    // Retrun Sunday following the Paschal moon
	return KdayOnOrBefore(paschalMoon+7, SUNDAY);
}

// For the Hebrew calendar all years are AM (anno mundi).
// One day is 24 hours
// One hour is 1080 parts; one hours is 1/12 of the interval between
// sunset and sunrise or 1/12 of the interval between sunrise and sunset.
// Hours therefore vary between day and night and with the seasons of the
// year. 1 Day = 25920 parts
// One part is 3 1/3 seconds
// One month is approx 29.5306 days (actual), 29.535094 days  (Hebrew)
// One Hebrew month is 29 days 12 hours 793 parts == 29 days 13753 parts
// One solar year is approx 365.2422 days
// Every 19 years there are 7 leap years making 235 months.

hebrewLeapYear(int year)
{
	return (year*7L + 1) % 19 < 7;
}

lastMonthOfHebrewYear(int year)
{	return hebrewLeapYear(year)?13:12;
}

// hebrewCalendarElapsedDays() returns the number of days since the
// Sunday prior to the start of the Hebrew calendar to the start of the
// year under consideration, i.e. the number of days since the creation
// of the world plus 1
// 1 Tishri 1 fell on Sunday night, 5 hours 204 parts, that is 1 day 5604
// parts after sunset on the preceding Saturday.
long hebrewCalendarElapsedDays(int year)
{
	long	months = 235L * ((year-1)/19) +   // Months in complete cycles
			 12 * ((year-1) % 19) + // regular months, this cycle
			 (1 + (7*((year-1)%19)))/19; // leap months, this cycle
#if 0		/* Needs very long arithmetic	*/
	long	parts	= 5604 + 13753L * months;
	long	day	= 1 + 29L*months + parts / 25920;

	parts	%= 25920;
#else		/* Uses only 24-bit arithmetic	*/
	long	parts_elapsed	= 204 + 793L *(months%1080);
	long	hours_elapsed	= 5 + 12L *months + 793L *(months/1080)
				    + parts_elapsed/1080;
	long	day		= 1 + 29L *months + hours_elapsed/24;
	long	parts		= 1080L  * (hours_elapsed%24) 
					+ parts_elapsed%1080;
#endif

	if (parts >= 19440 ||	// New moon is at or after noon
	    (day%7 == TUESDAY &&// or is a Tuesday ...
	     parts >= 9924 &&	// at 9 hours 204 parts or later ...
	     !hebrewLeapYear(year)	// of a common year
	    ) ||
	    (day%7 ==MONDAY &&	// .. or is a Monday at ...
	     parts >= 16789 &&	// ... 15 hours 589 parts or later ...
	     hebrewLeapYear(year-1)	// of a leap year
	    )
	   )
	    day+=1;		// Postpone by one day
	switch ((int)(day%7)) {
	case SUNDAY:		// If Rosh Hash-Hashana would fall on Sunday ...
	case WEDNESDAY:		// Wednesday or ...
	case FRIDAY:		// Friday ...
	    day+=1;		// postpone by one day
	    break;
	}

	return day;
}

daysInHebrewYear(int year)
{	return hebrewCalendarElapsedDays(year+1) -
		hebrewCalendarElapsedDays(year);
}

longHeshvanYear(int year)
{
	return  daysInHebrewYear(year) % 10 == 5;
}


shortKislevYear(int year)
{
	return  daysInHebrewYear(year) % 10 == 3;
}

// Nissan is month 1, Tishri is month 7
// NB Although months are numbered from Nissan, years are numbered from
// 1 Tishri!
lastDayOfHebrewMonth(int month, int year)
{
	switch (month) {
	case 2:
	case 4:
	case 6:
	case 10:
	case 13:
	    return 29;
	case 8:
	    if (!longHeshvanYear(year)) return 29;
	    break;
	case 9:
	    if(shortKislevYear(year)) return 29;
	    break;
	case 12:
	    if(!hebrewLeapYear(year)) return 29;
	    break;
	}
	return 30;
}


// HEBREW_EPOCH (-1373429) is the number of days between 1 Tishri 1 AM 
// and 1 Jan 1 Gregorian.
long absoluteFromHebrew(int day, int month, int year)
{	int	temp = day;

	if (month <7) {		// If before Tishri
	    for (int m=7; m <= lastMonthOfHebrewYear(year); m++)
		temp	+= lastDayOfHebrewMonth(m, year);
	    for (m=1; m < month; m++)
		temp	+= lastDayOfHebrewMonth(m, year);
	} else {
	    for (int m=7; m < month; m++)
		temp	+= lastDayOfHebrewMonth(m, year);
	}

	return hebrewCalendarElapsedDays(year) + temp + (HEBREW_EPOCH);
}

void hebrewFromAbsolute(long days, int& day, int& month, int& year)
{	
	year	= (days-(HEBREW_EPOCH))/ 366;
	for (int y = year; days >= absoluteFromHebrew(1, 7, y+1); y++)
	    year++;

// Because the year starts in month 7, we sometimes have to count the
// days of the year from Nissan and sometimes from Tishri
	month = (days < absoluteFromHebrew(1, 1, year))? 7 : 1;
	for (int m = month; days >
	    absoluteFromHebrew(lastDayOfHebrewMonth(m, year), m, year);
	    m++)
	    month++;

	day	= days - absoluteFromHebrew(1, month, year) + 1;
}

long roshHashana(int gregorianYear)
{	return	absoluteFromHebrew(1, 7, gregorianYear+3761);	}
long yomKippur(int gregorianYear)
{	return	absoluteFromHebrew(10, 7, gregorianYear+3761);	}
long succot(int gregorianYear)
{	return	absoluteFromHebrew(15, 7, gregorianYear+3761);	}
long pesach(int gregorianYear)
{	return	absoluteFromHebrew(15, 1, gregorianYear+3760);	}
long shavuot(int gregorianYear)
{	return	absoluteFromHebrew(6, 3, gregorianYear+3760);	}
long hanukka(int gregorianYear)
{	return	absoluteFromHebrew(25, 9, gregorianYear+3761);	}
long purim(int gregorianYear)
{	return absoluteFromHebrew(14,
			    lastMonthOfHebrewYear(gregorianYear+3760),
			    gregorianYear+3760);
}
long hebrewBirthday(int day, int month, int year, int gregorianYear)
{	long	absdate = absoluteFromGregorian(day, month, year);
	int	hd, hm, hy;
	long	absheb;
	int	approx;

    // Get the Hebrew date of birth
	hebrewFromAbsolute(absdate, hd, hm, hy);

    approx	= gregorianYear -year;
    do {
	if (hm ==lastMonthOfHebrewYear(hy)) {	// Might be 13th month
	    absheb = absoluteFromHebrew(hd, lastMonthOfHebrewYear(approx), approx);
	} else {
	    absheb = absoluteFromHebrew(hd, hm, approx);
	}
	gregorianFromAbsolute(absheb, day, month, year);
	approx	+= gregorianYear -year;
    } while (year != gregorianYear);
    return absheb;
}
\Rogue\Monster\
else
  echo "will not over write ./tmp/ZELLER.CPP"
fi
echo "Finished archive 1 of 1"
exit
--------------- Cut here ------------