Chelm.org's algorithms of the Jewish calendar


PATH : Chelm -> Jewish -> Calendar -> Algorithms
GREG_BASE_YEAR  = 1760
HEBR_BASE_YEAR  = 5530
BASE_MOLAD_DAY  = 3560
BASE_MOLAD_HOUR = 21
BASE_MOLAD_PART = 549

GREG_LEAP_YEAR(yr)  ((yr) % 4 == 0 && ((yr) % 100 != 0 || (yr) % 400 == 0))
HEBR_LEAP_YEAR(yr)  ((yr) % 19) == 0,3,6,8,11,14,17) ? YES : NO)

DAY_IN_WEEK(absolute_day)      (((absolute_day) + 2) % 7) 
    /* This works because absolute_day 1 is a Friday */

NORMALIZE_MOLAD(d,h,p)   (h)+=(p)/1080;p%=1080;(d)+=(h)/24;(h)%=24;
      /* basically make parts < 1080 and hours < 24 */

absolute_from_gregorian(month,day,year)
  {
  /* find out the difference of years from this year and base */
  /* multiply number of years by 365 */
  /* add in yeap years */
  /* subtract non-leap years on century years (-17 to start with year 1800) */
  /* add in leap years on 4 century years (-4 to account for years 400,800,1200 and 1600) */
  /* add in month */
  /* add in day */
  /* add a day for non-leap year correction */
  year_diffs    = year - GREG_BASE_YEAR;
  absolute_day  = (365 * year_diffs);      
  absolute_day += (year_diffs / 4);       
  absolute_day -= (year / 100) - 17; 
  absolute_day += (year / 400) - 4;  
  absolute_day += greg_month_starts[month]; 
    /* greg_month_starts = [ 0,31,60,91,121,152,182,213,244,274,305,335 ] */
  absolute_day += day - 1;                 
  if (!GREG_LEAP_YEAR(year) && month <= FEBRUARY)  
      absolute_day++;
  }

absolute_from_hebrew(month,day,year)
  {
  absolute_day = hebrew_find_rosh(year);
  for (loop = TISHREI;loop < month;loop = hebrew_next_month(loop))
    absolute_day += hebrew_days_in_month(loop);
  absolute_day += day - 1;
  }

gregorian_from_absolute(absolute_day) 
  {
  /* first guess at the rough year, then get the actual year from it, then
     the actual month and day */

  /* getting rough year */
  rough_year = absolute_day / 366;
  days = 365 * rough_year;
  days += (rough_year / 4);

  /* get actual year from it */
  year = rough_year + GREG_BASE_YEAR;
  if (!GREG_LEAP_YEAR(year))
    days++;
  days -= (year / 100) - 17;
  days += (year / 400) - 4;
  days = absolute_day - days;
  while (days >= (ydays = days_in_gregorian_year(year)))
    days -= ydays;
    year++;

  /* get month and day */
  for (month = 0;days >= (mdays = days_in_gregorian_month(month,year));month++)
    days -= mdays;
  day = days + 1;
  }

hebrew_from_absolute(absolute_day)
  {
  /* first find year - roughly under calculate year - take out chunks
     slighly bigger cycle or year to guarentee start at year at or
     before date */
  days = absolute_day - BASE_MOLAD_DAY;
  cycles = days / 6950;
  days -= cycles * 6950;
  for (delta = 0,loop = 1;
       days >= 0;
       delta++,days -= HEBR_LEAP_YEAR(loop) ? 358 : 388,loop++)
    ;
  /* have rough year, bounce it forward till you find the proper year */
  for (year = HEBR_BASE_YEAR + (19 * cycles) + delta - 1,
       year_date = hebrew_find_rosh(year),
       days = absolute_day;
      days >= (next_year_date = hebrew_find_rosh(year + 1));
      year++,year_date = next_year_date)
    ;

  days = absolute_day - hebrew_year_date;
  
  /* Now do months */
  for (month = TISHREI;
      days >= (delta = hebrew_days_in_month(month,year));
      days -= delta,month = hebrew_next_month(month,year))
    ;
  /* remainder is days */
  day = days + 1;
  }

hebrew_year_length = hebrew_find_rosh(year + 1) - hebrew_find_rosh(year);

int hebrew_find_rosh(int year) /* return absolute day of rosh for a year */
  /* calculate how many moons since base time */
  cycles = (hebrew_year - HEBR_BASE_YEAR) / 19;
  cycle_year = hebrew_year % 19;
  if (cycle_year == 0)
    cycle_year = 19;
  for (loop = 1,extra_months = 0;loop < cycle_year;loop++)
    extra_months += (HEBR_LEAP_YEAR(loop) ? 13 : 12);

  /* add in the number of moons to base time */
  molad_day = BASE_MOLAD_DAY + (6939 * cycles) + (29 * extra_months);
  molad_hour = BASE_MOLAD_HOUR + (16 * cycles) + (12 * extra_months);
  molad_part = BASE_MOLAD_PART + (595 * cycles) + (793 * extra_months);
  NORMALIZE_MOLAD(molad_day,molad_hour,molad_part);

  /* Now adjust Rosh date due to dehioth */
  weekday = DAY_IN_WEEK(molad_day);
  if (weekday == 0 || weekday == 3 || weekday == 5)
    molad_day++;
  else if (molad_hour >= 18)
    {
    if (weekday == 6 || weekday == 2 || weekday == 4)
      molad_day += 2;
    else
      molad_day++;
    }
  else if (!HEBR_LEAP_YEAR(hebrew_year) && weekday == 2 && 
	  ((molad_hour > 9) || (molad_hour == 9 && molad_part >= 204)))
    molad_day += 2; 
  else if (HEBR_LEAP_YEAR(hebrew_year - 1) && !HEBR_LEAP_YEAR(hebrew_year) && 
	   weekday == 1 && 
           ((molad_hour > 15) || (molad_hour == 15 && molad_part >= 589)))
    molad_day++;
  absolute_day = molad_day;
  }

hebrew_days_in_month(month,year) int month;int year;
  {
  case TISHREI : SHEVAT : ADAR_I : NISAN : SIVAN : AV : 30
  case TEVETH : ADAR_II : IYAR : TAMMUZ : ELUL        : 29
  case ADAR && hebrew_year_length > 360               : 30
  case HESHVAN && hebrew_year_length == 355,385       : 30
  case HESHVAN && hebrew_year_length != 355,385       : 29
  case KISLEV && hebrew_year_length == 353,383        : 29
  case KISLEV && hebrew_year_length != 353,383        : 30
  }

hebrew_next_month(month,year) int month; int year;
  {
  case TISHREI                 : HESHVAN
  case HESHVAN                 : KISLEV
  case KISLEV                  : TEVETH
  case TEVETH                  : SHEVAT
  case SHEVAT && leap_year     : ADAR_I
  case SHEVAT && not leap_year : ADAR
  case ADAR                    : NISAN
  case ADAR_I                  : ADAR_II;
  case ADAR_II                 : NISAN;
  case NISAN                   : IYAR
  case IYAR                    : SIVAN
  case SIVAN                   : TAMMUZ
  case TAMMUZ                  : AV
  case AV                      : ELUL
  case ELUL                    : TISHREI
  }
HOME       TOP       INDEX
FRAMES

PATH : Chelm -> Jewish -> Calendar -> Algorithms
Last updated on Aug 1, 1999 at 10:01 PM

Comments to stevenw@chelm.org

copyright 1999 - Steven Ross Weintraub