Attribute VB_Name = "HebrewToGregorian"
'---------------------------------------
' HebrewAndGregorian
'
' VB Port (c) 1999 by Trigeminal Software, Inc.
'
' The two functions to care about are
' GregorianDateOfHebrewDate
' HebrewDateOfGregorianDate
'
' Based on the original by Scott E. Lee
' available C source is at http://genealogy.org/~scottlee/
'
' Original Copyright info:
' $selId: jewish.c,v 2.0 1995/10/24 01:13:06 lees Exp $
' Copyright 1993-1995, Scott E. Lee, all rights reserved.
' Permission granted to use, copy, modify, distribute and sell so long as
' the above copyright and this permission statement are retained in all
' copies. THERE IS NO WARRANTY - USE AT YOUR OWN RISK.
'---------------------------------------
' The original comments from Scott E. Lee's code are preserved
' at the bottom of the module and discuss the functionality and
' relevant info on the two calendars
Option Compare Text
Option Explicit
Public a As Long, b As Long, c As Long
Private Const HALAKIM_PER_HOUR = 1080&
Private Const HALAKIM_PER_DAY = 25920&
Private Const HALAKIM_PER_LUNAR_CYCLE = ((29& * HALAKIM_PER_DAY) + 13753&)
Private Const HALAKIM_PER_METONIC_CYCLE = (HALAKIM_PER_LUNAR_CYCLE& * (12& * 19& + 7&))
Private Const SDN_OFFSETGREGORIAN = 32045
Private Const DAYS_PER_5_MONTHS = 153
Private Const DAYS_PER_4_YEARS = 1461
Private Const DAYS_PER_400_YEARS = 146097
Private Const SDN_OFFSET_HEBREW = 347997
Private Const NEW_MOON_OF_CREATION = 31524
Private Const SUNDAY = vbSunday - 1
Private Const MONDAY = vbMonday - 1
Private Const TUESDAY = vbTuesday - 1
Private Const WEDNESDAY = vbWednesday - 1
Private Const THURSDAY = vbThursday - 1
Private Const FRIDAY = vbFriday - 1
Private Const SATURDAY = vbSaturday - 1
Private Const NOON = (18 * HALAKIM_PER_HOUR)
Private Const AM3_11_20 = ((9 * HALAKIM_PER_HOUR) + 204)
Private Const AM9_32_43 = ((15 * HALAKIM_PER_HOUR) + 589)
Private Property Get m_monthsPerYear() As Variant
m_monthsPerYear = Array(12&, 12&, 13&, 12&, 12&, 13&, 12&, 13&, 12&, 12&, 13&, 12&, 12&, 13&, 12&, 12&, 13&, 12&, 13&)
End Property
Private Property Get m_yearOffset() As Variant
m_yearOffset = Array(0&, 12&, 24&, 37&, 49&, 61&, 74&, 86&, 99&, 111&, 123&, 136&, 148&, 160&, 173&, 185&, 197&, 210&, 222&)
End Property
'------------------------------------
' GregorianDateOfHebrewDate
'
' Takes the Hebrew Year/Month/Day and
' returns the Gregorian date in a VBA date
' variable
'------------------------------------
Public Function GregorianDateOfHebrewDate( _
ByVal hYear As Long, _
ByVal hMonth As Long, _
ByVal hDay As Long) As Date
Dim sdn As Long
Dim gYear As Long
Dim gMonth As Long
Dim gDay As Long
sdn = JewishToSdn(hYear, hMonth, hDay)
Call SdnToGregorian(sdn, gYear, gMonth, gDay)
GregorianDateOfHebrewDate = DateSerial(gYear, gMonth, gDay)
End Function
'------------------------------------
' HebrewDateOfGregorianDate
'
' Takes the Gregorian date and
' returns the Hebrew Year/Month/Day
' into the provided variables
'------------------------------------
Public Sub HebrewDateOfGregorianDate( _
ByVal dte As Date, _
ByRef hYear As Long, _
ByRef hMonth As Long, _
ByRef hDay As Long)
Dim sdn As Long
sdn = GregorianToSdn(year(dte), month(dte), day(dte))
Call SdnToJewish(sdn, hYear, hMonth, hDay)
End Sub
'***********************************************************************
' Given the year within the 19 year metonic cycle and the time of a molad
' (new moon) which starts that year, this routine will calculate what day
' will be the actual start of the year (Tishri 1 or Rosh Ha-Shanah). This
' first day of the year will be the day of the molad unless one of 4 rules
' (called dehiyyot) delays it. These 4 rules can delay the start of the
' year by as much as 2 days.
Private Function tishri1( _
ByVal metonicYear As Long, _
ByVal moladDay As Long, _
ByVal moladHalakim As Long) As Long
Dim lTishri1 As Long
Dim dow As Long
Dim leapYear As Long
Dim lastWasLeapYear As Long
lTishri1 = moladDay
dow = lTishri1 Mod 7
leapYear = (metonicYear = 2) Or (metonicYear = 5) Or (metonicYear = 7) Or _
(metonicYear = 10) Or (metonicYear = 13) Or (metonicYear = 16) Or _
(metonicYear = 18)
lastWasLeapYear = (metonicYear = 3) Or (metonicYear = 6) Or (metonicYear = 8) Or _
(metonicYear = 11) Or (metonicYear = 14) Or (metonicYear = 17) Or _
(metonicYear = 0)
' Apply rules 2, 3 and 4.
If (( _
moladHalakim >= NOON) Or _
((Abs(Not leapYear) And dow = TUESDAY) And (moladHalakim >= AM3_11_20)) Or _
((Abs(lastWasLeapYear) And dow = MONDAY) And (moladHalakim >= AM9_32_43))) Then
lTishri1 = lTishri1 + 1
dow = dow + 1
If (dow = 7) Then dow = 0
End If
' Apply rule 1 after the others because it can cause an additional delay of one day.
If (dow = WEDNESDAY Or dow = FRIDAY Or dow = SUNDAY) Then lTishri1 = lTishri1 + 1
tishri1 = lTishri1
End Function
'***********************************************************************
' Given a metonic cycle number, calculate the date and time of the molad
' (new moon) that starts that cycle. Since the length of a metonic cycle
' is a constant, this is a simple calculation, except that it requires an
' intermediate value which is bigger that 32 bits. Because this
' intermediate value only needs 36 to 37 bits and the other numbers are
' constants, the process has been reduced to just a few steps.
Private Function MoladOfMetonicCycle( _
ByVal metonicCycle As Long, _
ByRef pMoladDay As Long, _
ByRef pMoladHalakim As Long) As Long
Dim halakim As Variant
Dim r1 As Variant
Dim d1 As Variant
' Start with the time of the first molad after creation.
' (Note that one CDec() is all we need to have all of
' the variants be treated as vbDecimal)
halakim = CDec(NEW_MOON_OF_CREATION)
' Calculate metonicCycle * HALAKIM_PER_METONIC_CYCLE.
' The result will be in halakim.
halakim = halakim + (CDec(metonicCycle) * HALAKIM_PER_METONIC_CYCLE)
' Calculate halakim / HALAKIM_PER_DAY. The remainder
' will be in r1, the quotient will be in d1.
d1 = halakim / HALAKIM_PER_DAY
r1 = (d1 - Int(d1)) * HALAKIM_PER_DAY
d1 = Int(d1)
pMoladDay = d1
pMoladHalakim = r1
End Function
'***********************************************************************
' Given a day number, find the molad of Tishri (the new moon at the start
' of a year) which is closest to that day number. It's not really the
' *closest* molad that we want here. If the input day is in the first two
' months, we want the molad at the start of the year. If the input day is
' in the fourth to last months, we want the molad at the end of the year.
' If the input day is in the third month, it doesn't matter which molad is
' returned, because both will be required. This type of "rounding" allows
' us to avoid calculating the length of the year in most cases.
Private Function FindTishriMolad( _
ByVal inputDay As Long, _
ByRef pMetonicCycle As Long, _
ByRef pMetonicYear As Long, _
ByRef pMoladDay As Long, _
ByRef pMoladHalakim As Long) As Long
Dim moladDay As Long
Dim moladHalakim As Long
Dim metonicCycle As Long
Dim metonicYear As Long
Dim monthsPerYear As Variant
' Estimate the metonic cycle number. Note that this may be an under
' estimate because there are 6939.6896 days in a metonic cycle not
' 6940, but it will never be an over estimate. The loop below will
' correct for any error in this estimate.
'
' SPECIAL THANKS to randki, for the post in comp.databases.ms-access
' that fixed the error in the code below which made many
' dates fail.
'
metonicCycle = (inputDay + 310) \ 6940
' Calculate the time of the starting molad for this metonic cycle.
Call MoladOfMetonicCycle(metonicCycle, moladDay, moladHalakim)
' If the above was an under estimate, increment the cycle number until
' the correct one is found. For modern dates this loop is about 98.6%
' likely to not execute, even once, because the above estimate is
' really quite close.
Do While (moladDay < inputDay - 6940 + 310)
metonicCycle = metonicCycle + 1
moladHalakim = moladHalakim + HALAKIM_PER_METONIC_CYCLE
moladDay = moladDay + moladHalakim \ HALAKIM_PER_DAY
moladHalakim = moladHalakim Mod HALAKIM_PER_DAY
Loop
' Find the molad of Tishri closest to this date.
For metonicYear = 0 To 17 Step 1
If (moladDay > inputDay - 74) Then Exit For
monthsPerYear = m_monthsPerYear
moladHalakim = moladHalakim + HALAKIM_PER_LUNAR_CYCLE * monthsPerYear(metonicYear)
moladDay = moladDay + moladHalakim \ HALAKIM_PER_DAY
moladHalakim = moladHalakim Mod HALAKIM_PER_DAY
Next metonicYear
pMetonicCycle = metonicCycle
pMetonicYear = metonicYear
pMoladDay = moladDay
pMoladHalakim = moladHalakim
End Function
'***********************************************************************
' Given a year, find the number of the first day of that year and the date
' and time of the starting molad.
Private Function FindStartOfYear( _
ByVal year As Long, _
ByRef pMetonicCycle As Long, _
ByRef pMetonicYear As Long, _
ByRef pMoladDay As Long, _
ByRef pMoladHalakim As Long, _
ByRef pTishri1 As Long) As Long
Dim yearOffset As Variant
pMetonicCycle = (year - 1) \ 19
pMetonicYear = (year - 1) Mod 19
Call MoladOfMetonicCycle(pMetonicCycle, pMoladDay, pMoladHalakim)
yearOffset = m_yearOffset
pMoladHalakim = pMoladHalakim + HALAKIM_PER_LUNAR_CYCLE * yearOffset(pMetonicYear)
pMoladDay = pMoladDay + pMoladHalakim \ HALAKIM_PER_DAY
pMoladHalakim = pMoladHalakim Mod HALAKIM_PER_DAY
pTishri1 = tishri1(pMetonicYear, pMoladDay, pMoladHalakim)
End Function
'***********************************************************************
' Given a serial day number (SDN), find the corresponding year, month and
' day in the Jewish calendar. The three output values will always be
' modified. If the input SDN is before the first day of year 1, they will
' all be set to zero, otherwise *pYear will be > 0; *pMonth will be in the
' range 1 to 13 inclusive; *pDay will be in the range 1 to 30 inclusive.
Public Sub SdnToJewish( _
ByVal sdn As Long, _
ByRef pYear As Long, _
ByRef pMonth As Long, _
ByRef pDay As Long)
Dim inputDay As Long
Dim day As Long
Dim halakim As Long
Dim metonicCycle As Long
Dim metonicYear As Long
Dim lTishri1 As Long
Dim tishri1After As Long
Dim yearLength As Long
Dim monthsPerYear As Variant
If (sdn <= SDN_OFFSET_HEBREW) Then
pYear = 0
pMonth = 0
pDay = 0
Exit Sub
End If
inputDay = sdn - SDN_OFFSET_HEBREW
Call FindTishriMolad(inputDay, metonicCycle, metonicYear, day, halakim)
lTishri1 = tishri1(metonicYear, day, halakim)
monthsPerYear = m_monthsPerYear
If (inputDay >= lTishri1) Then
' It found Tishri 1 at the start of the year.
pYear = metonicCycle * 19 + metonicYear + 1
If (inputDay < lTishri1 + 59) Then
If (inputDay < lTishri1 + 30) Then
pMonth = 1
pDay = inputDay - lTishri1 + 1
Else
pMonth = 2
pDay = inputDay - lTishri1 - 29
End If
Exit Sub
End If
' We need the length of the year to figure this out, so find
' Tishri 1 of the next year.
halakim = halakim + HALAKIM_PER_LUNAR_CYCLE * monthsPerYear(metonicYear)
day = day + halakim \ HALAKIM_PER_DAY
halakim = halakim Mod HALAKIM_PER_DAY
tishri1After = tishri1((metonicYear + 1) Mod 19, day, halakim)
Else
' It found Tishri 1 at the end of the year.
pYear = metonicCycle * 19 + metonicYear
If (inputDay >= lTishri1 - 177) Then
' It is one of the last 6 months of the year.
If (inputDay > lTishri1 - 30) Then
pMonth = 13
pDay = inputDay - lTishri1 + 30
ElseIf (inputDay > lTishri1 - 60) Then
pMonth = 12
pDay = inputDay - lTishri1 + 60
ElseIf (inputDay > lTishri1 - 89) Then
pMonth = 11
pDay = inputDay - lTishri1 + 89
ElseIf (inputDay > lTishri1 - 119) Then
pMonth = 10
pDay = inputDay - lTishri1 + 119
ElseIf (inputDay > lTishri1 - 148) Then
pMonth = 9
pDay = inputDay - lTishri1 + 148
Else
pMonth = 8
pDay = inputDay - lTishri1 + 178
End If
Exit Sub
Else
If (monthsPerYear((pYear - 1) Mod 19) = 13) Then
pMonth = 7
pDay = inputDay - lTishri1 + 207
If (pDay > 0) Then Exit Sub
pMonth = pMonth - 1
pDay = pDay + 30
If (pDay > 0) Then Exit Sub
pMonth = pMonth - 1
pDay = pDay + 30
Else
pMonth = 6
pDay = inputDay - lTishri1 + 207
If (pDay > 0) Then Exit Sub
pMonth = pMonth - 1
pDay = pDay + 30
End If
If (pDay > 0) Then Exit Sub
pMonth = pMonth - 1
pDay = pDay + 29
If (pDay > 0) Then Exit Sub
' We need the length of the year to figure this out, so find
' Tishri 1 of this year.
tishri1After = lTishri1
Call FindTishriMolad(day - 365, metonicCycle, metonicYear, day, halakim)
lTishri1 = tishri1(metonicYear, day, halakim)
End If
End If
yearLength = tishri1After - lTishri1
day = inputDay - lTishri1 - 29
If (yearLength = 355 Or yearLength = 385) Then
' Heshvan has 30 days
If (day <= 30) Then
pMonth = 2
pDay = day
Exit Sub
End If
day = day - 30
Else
' Heshvan has 29 days
' Heshvan has 30 days
If (day <= 29) Then
pMonth = 2
pDay = day
Exit Sub
End If
day = day - 29
End If
' It has to be Kislev.
pMonth = 3
pDay = day
End Sub
'***********************************************************************
' Given a year, month and day in the Jewish calendar, find the
' corresponding serial day number (SDN). Zero is returned when the input
' date is detected as invalid. The return value will be > 0 for all valid
' dates, but there are some invalid dates that will return a positive
' value. To verify that a date is valid, convert it to SDN and then back
' and compare with the original.
Public Function JewishToSdn( _
ByVal year As Long, _
ByVal month As Long, _
ByVal day As Long) As Long
Dim sdn As Long
Dim metonicCycle As Long
Dim metonicYear As Long
Dim lTishri1 As Long
Dim tishri1After As Long
Dim moladDay As Long
Dim moladHalakim As Long
Dim yearLength As Long
Dim lengthOfAdarIAndII As Long
Dim monthsPerYear As Variant
If (year <= 0 Or day <= 0 Or day > 30) Then
JewishToSdn = 0
Exit Function
End If
monthsPerYear = m_monthsPerYear
Select Case month
Case 1, 2
' It is Tishri or Heshvan - don't need the year length.
Call FindStartOfYear(year, metonicCycle, metonicYear, moladDay, moladHalakim, lTishri1)
If (month = 1) Then
sdn = lTishri1 + day - 1
Else
sdn = lTishri1 + day + 29
End If
Case 3
' It is Kislev - must find the year length.
' Find the start of the year.
Call FindStartOfYear(year, metonicCycle, metonicYear, moladDay, moladHalakim, lTishri1)
' Find the end of the year.
moladHalakim = moladHalakim + HALAKIM_PER_LUNAR_CYCLE * monthsPerYear(metonicYear)
moladDay = moladDay + moladHalakim \ HALAKIM_PER_DAY
moladHalakim = moladHalakim Mod HALAKIM_PER_DAY
tishri1After = tishri1((metonicYear + 1) Mod 19, moladDay, moladHalakim)
yearLength = tishri1After - lTishri1
If (yearLength = 355 Or yearLength = 385) Then
sdn = lTishri1 + day + 59
Else
sdn = lTishri1 + day + 58
End If
Case 4, 5, 6
' It is Tevet, Shevat or Adar I - don't need the year length.
Call FindStartOfYear(year + 1, metonicCycle, metonicYear, moladDay, moladHalakim, tishri1After)
If (monthsPerYear((year - 1) Mod 19) = 12) Then
lengthOfAdarIAndII = 29
Else
lengthOfAdarIAndII = 59
End If
If (month = 4) Then
sdn = tishri1After + day - lengthOfAdarIAndII - 237
ElseIf (month = 5) Then
sdn = tishri1After + day - lengthOfAdarIAndII - 208
Else
sdn = tishri1After + day - lengthOfAdarIAndII - 178
End If
Case Else
' It is Adar II or later - don't need the year length.
Call FindStartOfYear(year + 1, metonicCycle, metonicYear, moladDay, moladHalakim, tishri1After)
Select Case (month)
Case 7
sdn = tishri1After + day - 207
Case 8
sdn = tishri1After + day - 178
Case 9
sdn = tishri1After + day - 148
Case 10
sdn = tishri1After + day - 119
Case 11
sdn = tishri1After + day - 89
Case 12
sdn = tishri1After + day - 60
Case 13
sdn = tishri1After + day - 30
Case Else
JewishToSdn = 0
Exit Function
End Select
End Select
JewishToSdn = (sdn + SDN_OFFSET_HEBREW)
End Function
'----------------------------------------------------------------------
' LeftShift
'
' Since VB does not have a left shift operator
' LeftShift(8,2) is equivalent to 8 << 2
'----------------------------------------------------------------------
Private Function LeftShift(ByVal lNum As Currency, ByVal lShift As Currency) As Currency
LeftShift = lNum * (2 ^ lShift)
End Function
'----------------------------------------------------------------------
' RightShift
'
' Since VB does not have a right shift operator
' RightShift(8,2) is equivalent to 8 >> 2
'----------------------------------------------------------------------
Private Function RightShift(ByVal lNum As Currency, ByVal lShift As Currency) As Currency
RightShift = Round(lNum / (2 ^ lShift))
End Function
Public Sub SdnToGregorian(sdn As Long, pYear As Long, pMonth As Long, pDay As Long)
Dim century As Long
Dim year As Long
Dim month As Long
Dim day As Long
Dim temp As Long
Dim dayOfYear As Long
If (sdn <= 0) Then
pYear = 0
pMonth = 0
pDay = 0
Exit Sub
End If
temp = (sdn + SDN_OFFSETGREGORIAN) * 4 - 1
' Calculate the century (year/100).
century = temp \ DAYS_PER_400_YEARS
' Calculate the year and day of year (1 <= dayOfYear <= 366).
temp = ((temp Mod DAYS_PER_400_YEARS) \ 4) * 4 + 3
year = (century * 100) + (temp \ DAYS_PER_4_YEARS)
dayOfYear = (temp Mod DAYS_PER_4_YEARS) \ 4 + 1
' Calculate the month and day of month.
temp = dayOfYear * 5 - 3
month = temp \ DAYS_PER_5_MONTHS
day = (temp Mod DAYS_PER_5_MONTHS) \ 5 + 1
' Convert to the normal beginning of the year.
If (month < 10) Then
month = month + 3
Else
year = year + 1
month = month - 9
End If
' Adjust to the B.C./A.D. type numbering.
year = year - 4800
If (year <= 0) Then year = year - 1
pYear = year
pMonth = month
pDay = day
End Sub
Public Function GregorianToSdn(inputYear As Long, inputMonth As Long, inputDay As Long) As Long
Dim year As Long
Dim month As Long
' check for invalid dates
If ( _
inputYear = 0 Or inputYear < -4714 Or _
inputMonth <= 0 Or inputMonth > 12 Or _
inputDay <= 0 Or inputDay > 31) Then
Exit Function
End If
' check for dates before SDN 1 (Nov 25, 4714 B.C.)
If (inputYear = -4714) Then
If (inputMonth < 11) Then Exit Function
If (inputMonth = 11 And inputDay < 25) Then Exit Function
End If
' Make year always a positive number.
If (inputYear < 0) Then
year = inputYear + 4801
Else
year = inputYear + 4800
End If
' Adjust the start of the year.
If (inputMonth > 2) Then
month = inputMonth - 3
Else
month = inputMonth + 9
year = year - 1
End If
GregorianToSdn = (((year \ 100) * DAYS_PER_400_YEARS) \ 4 _
+ ((year Mod 100) * DAYS_PER_4_YEARS) \ 4 _
+ (month * DAYS_PER_5_MONTHS + 2) \ 5 _
+ inputDay - SDN_OFFSETGREGORIAN)
End Function
'
' These are the externally visible components of this file:
'
' void
' SdnToJewish(
' long int sdn,
' int'pYear,
' int'pMonth,
' int'pDay);
'
' Convert a SDN to a Jewish calendar date. If the input SDN is before the
' first day of year 1, the three output values will all be set to zero,
' otherwise'pYear will be > 0;'pMonth will be in the range 1 to 13
' inclusive;'pDay will be in the range 1 to 30 inclusive. Note that Adar
' II is assigned the month number 7 and Elul is always 13.
'
' long int
' JewishToSdn(
' int year,
' int month,
' int day);
'
' Convert a Jewish calendar date to a SDN. Zero is returned when the
' input date is detected as invalid or out of the supported range. The
' return value will be > 0 for all valid, supported dates, but there are
' some invalid dates that will return a positive value. To verify that a
' date is valid, convert it to SDN and then back and compare with the
' original.
'
' VALID RANGE
'
' Although this software can handle dates all the way back to the year
' 1 (3761 B.C.), such use may not be meaningful.
'
' The Jewish calendar has been in use for several thousand years, but
' in the early days there was no formula to determine the start of a
' month. A new month was started when the new moon was first
' observed.
'
' It is not clear when the current rule based calendar replaced the
' observation based calendar. According to the book "Jewish Calendar
' Mystery Dispelled" by George Zinberg, the patriarch Hillel II
' published these rules in 358 A.D. But, according to The
' Encyclopedia Judaica, Hillel II may have only published the 19 year
' rule for determining the occurrence of leap years.
'
' I have yet to find a specific date when the current set of rules
' were known to be in use.
'
' CALENDAR OVERVIEW
'
' The Jewish calendar is based on lunar as well as solar cycles. A
' month always starts on or near a new moon and has either 29 or 30
' days (a lunar cycle is about 29 1/2 days). Twelve of these
' alternating 29-30 day months gives a year of 354 days, which is
' about 11 1/4 days short of a solar year.
'
' Since a month is defined to be a lunar cycle (new moon to new moon),
' this 11 1/4 day difference cannot be overcome by adding days to a
' month as with the Gregorian calendar, so an entire month is
' periodically added to the year, making some years 13 months long.
'
' For astronomical as well as ceremonial reasons, the start of a new
' year may be delayed until a day or two after the new moon causing
' years to vary in length. Leap years can be from 383 to 385 days and
' common years can be from 353 to 355 days. These are the months of
' the year and their possible lengths:
'
' COMMON YEAR LEAP YEAR
' 1 Tishri 30 30 30 30 30 30
' 2 Heshvan 29 29 30 29 29 30 (variable)
' 3 Kislev 29 30 30 29 30 30 (variable)
' 4 Tevet 29 29 29 29 29 29
' 5 Shevat 30 30 30 30 30 30
' 6 Adar I 29 29 29 30 30 30 (variable)
' 7 Adar II -- -- -- 29 29 29 (optional)
' 8 Nisan 30 30 30 30 30 30
' 9 Iyyar 29 29 29 29 29 29
' 10 Sivan 30 30 30 30 30 30
' 11 Tammuz 29 29 29 29 29 29
' 12 Av 30 30 30 30 30 30
' 13 Elul 29 29 29 29 29 29
' --- --- --- --- --- ---
' 353 354 355 383 384 385
'
' Note that the month names and other words that appear in this file
' have multiple possible spellings in the Roman character set. I have
' chosen to use the spellings found in the Encyclopedia Judaica.
'
' Adar II, the month added for leap years, is sometimes referred to as
' the 13th month, but I have chosen to assign it the number 7 to keep
' the months in chronological order. This may not be consistent with
' other numbering schemes.
'
' Leap years occur in a fixed pattern of 19 years called the metonic
' cycle. The 3rd, 6th, 8th, 11th, 14th, 17th and 19th years of this
' cycle are leap years. The first metonic cycle starts with Jewish
' year 1, or 3761/60 B.C. This is believed to be the year of
' creation.
'
' To construct the calendar for a year, you must first find the length
' of the year by determining the first day of the year (Tishri 1, or
' Rosh Ha-Shanah) and the first day of the following year. This
' selects one of the six possible month length configurations listed
' above.
'
' Finding the first day of the year is the most difficult part.
' Finding the date and time of the new moon (or molad) is the first
' step. For this purpose, the lunar cycle is assumed to be 29 days 12
' hours and 793 halakim. A halakim is 1/1080th of an hour or 3 1/3
' seconds. (This assumed value is only about 1/2 second less than the
' value used by modern astronomers -- not bad for a number that was
' determined so long ago.) The first molad of year 1 occurred on
' Sunday at 11:20:11 P.M. This would actually be Monday, because the
' Jewish day is considered to begin at sunset.
'
' Since sunset varies, the day is assumed to begin at 6:00 P.M. for
' calendar calculation purposes. So, the first molad was 5 hours 793
' halakim after the start of Tishri 1, 0001 (which was Monday
' September 7, 4761 B.C. by the Gregorian calendar). All subsequent
' molads can be calculated from this starting point by adding the
' length of a lunar cycle.
'
' Once the molad that starts a year is determined the actual start of
' the year (Tishri 1) can be determined. Tishri 1 will be the day of
' the molad unless it is delayed by one of the following four rules
' (called dehiyyot). Each rule can delay the start of the year by one
' day, and since rule #1 can combine with one of the other rules, it
' can be delayed as much as two days.
'
' 1. Tishri 1 must never be Sunday, Wednesday or Friday. (This
' is largely to prevent certain holidays from occurring on the
' day before or after the Sabbath.)
'
' 2. If the molad occurs on or after noon, Tishri 1 must be
' delayed.
'
' 3. If it is a common (not leap) year and the molad occurs on
' Tuesday at or after 3:11:20 A.M., Tishri 1 must be delayed.
'
' 4. If it is the year following a leap year and the molad occurs
' on Monday at or after 9:32:43 and 1/3 sec, Tishri 1 must be
' delayed.
'
' GLOSSARY
'
' dehiyyot The set of 4 rules that determine when the new year
' starts relative to the molad.
'
' halakim 1/1080th of an hour or 3 1/3 seconds.
'
' lunar cycle The period of time between mean conjunctions of the
' sun and moon (new moon to new moon). This is
' assumed to be 29 days 12 hours and 793 halakim for
' calendar purposes.
'
' metonic cycle A 19 year cycle which determines which years are
' leap years and which are common years. The 3rd,
' 6th, 8th, 11th, 14th, 17th and 19th years of this
' cycle are leap years.
'
' molad The date and time of the mean conjunction of the
' sun and moon (new moon). This is the approximate
' beginning of a month.
'
' Rosh Ha-Shanah The first day of the Jewish year (Tishri 1).
'
' Tishri The first month of the Jewish year.
'
' ALGORITHMS
'
' SERIAL DAY NUMBER TO JEWISH DATE
'
' The simplest approach would be to use the rules stated above to find
' the molad of Tishri before and after the given day number. Then use
' the molads to find Tishri 1 of the current and following years.
' From this the length of the year can be determined and thus the
' length of each month. But this method is used as a last resort.
'
' The first 59 days of the year are the same regardless of the length
' of the year. As a result, only the day number of the start of the
' year is required.
'
' Similarly, the last 6 months do not change from year to year. And
' since it can be determined whether the year is a leap year by simple
' division, the lengths of Adar I and II can be easily calculated. In
' fact, all dates after the 3rd month are consistent from year to year
' (once it is known whether it is a leap year).
'
' This means that if the given day number falls in the 3rd month or on
' the 30th day of the 2nd month the length of the year must be found,
' but in no other case.
'
' So, the approach used is to take the given day number and round it
' to the closest molad of Tishri (first new moon of the year). The
' rounding is not really to the'closest* molad, but is such that if
' the day number is before the middle of the 3rd month the molad at
' the start of the year is found, otherwise the molad at the end of
' the year is found.
'
' Only if the day number is actually found to be in the ambiguous
' period of 29 to 31 days is the other molad calculated.
'
' JEWISH DATE TO SERIAL DAY NUMBER
'
' The year number is used to find which 19 year metonic cycle contains
' the date and which year within the cycle (this is a division and
' modulus). This also determines whether it is a leap year.
'
' If the month is 1 or 2, the calculation is simple addition to the
' first of the year.
'
' If the month is 8 (Nisan) or greater, the calculation is simple
' subtraction from beginning of the following year.
'
' If the month is 4 to 7, it is considered whether it is a leap year
' and then simple subtraction from the beginning of the following year
' is used.
'
' Only if it is the 3rd month is both the start and end of the year
' required.
'
' TESTING
'
' This algorithm has been tested in two ways. First, 510 dates from a
' table in "Jewish Calendar Mystery Dispelled" were calculated and
' compared to the table. Second, the calculation algorithm described
' in "Jewish Calendar Mystery Dispelled" was coded and used to verify
' all dates from the year 1 (3761 B.C.) to the year 13760 (10000
' A.D.).
'
' The source code of the verification program is included in this
' package.
'
' REFERENCES
'
' The Encyclopedia Judaica, the entry for "Calendar"
'
' The Jewish Encyclopedia
'
' Jewish Calendar Mystery Dispelled by George Zinberg, Vantage Press,
' 1963
'
' The Comprehensive Hebrew Calendar by Arthur Spier, Behrman House
'
' The Book of Calendars [note that this work contains many typos]
'
'************************************************************************
'*************************************************************************
'
' These are the externally visible components of this file:
'
' void
' SdnToGregorian(
' long int sdn,
' int *pYear,
' int *pMonth,
' int *pDay);
'
' Convert a SDN to a Gregorian calendar date. If the input SDN is less
' than 1, the three output values will all be set to zero, otherwise
' *pYear will be >= -4714 and != 0; *pMonth will be in the range 1 to 12
' inclusive; *pDay will be in the range 1 to 31 inclusive.
'
' long int
' GregorianToSdn(
' int inputYear,
' int inputMonth,
' int inputDay);
'
' Convert a Gregorian calendar date to a SDN. Zero is returned when the
' input date is detected as invalid or out of the supported range. The
' return value will be > 0 for all valid, supported dates, but there are
' some invalid dates that will return a positive value. To verify that a
' date is valid, convert it to SDN and then back and compare with the
' original.
'
' VALID RANGE
'
' 4714 B.C. to at least 10000 A.D.
'
' Although this software can handle dates all the way back to 4714
' B.C., such use may not be meaningful. The Gregorian calendar was
' not instituted until October 15, 1582 (or October 5, 1582 in the
' Julian calendar). Some countries did not accept it until much
' later. For example, Britain converted in 1752, The USSR in 1918 and
' Greece in 1923. Most European countries used the Julian calendar
' prior to the Gregorian.
'
' CALENDAR OVERVIEW
'
' The Gregorian calendar is a modified version of the Julian calendar.
' The only difference being the specification of leap years. The
' Julian calendar specifies that every year that is a multiple of 4
' will be a leap year. This leads to a year that is 365.25 days long,
' but the current accepted value for the tropical year is 365.242199
' days.
'
' To correct this error in the length of the year and to bring the
' vernal equinox back to March 21, Pope Gregory XIII issued a papal
' bull declaring that Thursday October 4, 1582 would be followed by
' Friday October 15, 1582 and that centennial years would only be a
' leap year if they were a multiple of 400. This shortened the year
' by 3 days per 400 years, giving a year of 365.2425 days.
'
' Another recently proposed change in the leap year rule is to make
' years that are multiples of 4000 not a leap year, but this has never
' been officially accepted and this rule is not implemented in these
' algorithms.
'
' ALGORITHMS
'
' The calculations are based on three different cycles: a 400 year
' cycle of leap years, a 4 year cycle of leap years and a 5 month
' cycle of month lengths.
'
' The 5 month cycle is used to account for the varying lengths of
' months. You will notice that the lengths alternate between 30
' and 31 days, except for three anomalies: both July and August
' have 31 days, both December and January have 31, and February
' is less than 30. Starting with March, the lengths are in a
' cycle of 5 months (31, 30, 31, 30, 31):
'
' Mar 31 days \
' Apr 30 days |
' May 31 days > First cycle
' Jun 30 days |
' Jul 31 days /
'
' Aug 31 days \
' Sep 30 days |
' Oct 31 days > Second cycle
' Nov 30 days |
' Dec 31 days /
'
' Jan 31 days \
' Feb 28/9 days |
' > Third cycle (incomplete)
'
' For this reason the calculations (internally) assume that the
' year starts with March 1.
'
' TESTING
'
' This algorithm has been tested from the year 4714 B.C. to 10000
' A.D. The source code of the verification program is included in
' this package.
'
' REFERENCES
'
' Conversions Between Calendar Date and Julian Day Number by Robert J.
' Tantzen, Communications of the Association for Computing Machinery
' August 1963. (Also published in Collected Algorithms from CACM,
' algorithm number 199).
'
'************************************************************************