Creator of the Symmetry454 CalendarArithmetic of the Bahá'í Calendar, and Variants

Bookmark or cite this page as <http://www.sym454.org/bahai/>

Created by Dr. Irv Bromberg, University of Toronto, Canada email icon

[Click here to go back to the Symmetry454 / Kalendis home page]

After learning about the fascinating and novel Bahá'í calendar, out of curiosity I explored several variants of it. This web page presents my public domain implementation of the arithmetic of the standard Western Bahá'í calendar, along with several experimental "Bahá'í-inspired" calendar variants.


Menu of Topics:

  1. The Bahá'í Calendar — also known as the Badí (Wonderful) Calendar
  2. Overview of Variants of the Bahá'í Calendar
  3. Position of the Intercalary Days
  4. Fixed Dates — the Rata Die
  5. Calculation Precision — the Limitations of "Floating Point" Arithmetic
  6. Copying Formulae or Statements and Pasting into Other Applications
  7. The All-Important New Year Day (Naw-Rúz)
  8. A Leap Day Variant With Uniformly Spread Leap Years
  9. A Perpetual Leap Week Variant With Uniformly Spread Leap Years
  10. A Leap Month Variant With Uniformly Spread Leap Years
  11. The Bahá'í Calendar Mode
  12. Constants
  13. The YearToElapsedMonths and ElapsedMonthsToFixed Functions
  14. The Naw-Rúz Function
  15. The isLeapYear Function
  16. The IntercalaryDays Function
  17. The FixedToBahai Function
  18. The BahaiToFixed Function
  19. Converting Bahá'í Dates
  20. Checking if a Date is Valid
  21. Random Date Validation

The Bahá'í Calendar — also known as the Badí (Wonderful) Calendar

(According to Google, the Arabic word Badí also translates as adorable, magnificent, splendid, superb, marvelous, fine, admirable, unique, amazing, unprecedented, excellent, or original. This word is also used as the name of the 16th year of each 19-year cycle, in which case it is typically translated as beginning.)

The Friends (members) of the Bahá'í Faith follow a novel and unique calendar having 19 days per month, 19 months per year, 19 years per cycle, and 19 cycles per major.

As 19 days × 19 months = 361 days, in a non-leap year the calendar has 4 intercalated days inserted as a "null" month between the 18th and 19th months, whereas in leap years there are 5 such intercalated days.

The founders of the Bahá'í calendar intended that the New Year Day (Naw-Rúz) should be that day upon which the northward equinox occurs prior to sunset at a specified location. The Bahá'í, however, have not yet decided upon that location, so at present the "Eastern" Bahá'í tend to start the year on the same day as the Persian calendar, because the faith originated in Persia and because the Persian calendar starts its year according to a similar rule (referenced to Iran Standard Time).

The "Western" Bahá'í (living in the Americas), however, prefer to maintain a consistent relationship relative to Gregorian calendar dates, so they start the Bahá'í calendar year on Gregorian March 21st, even though the latter is now always at least one day after the northward equinox. As the intercalary days span Gregorian February 29th, each month on the Western Bahá'í calendar has a permanently fixed starting date on the Gregorian calendar, as shown in this chart at the Bahá'í USA web site. Western Bahá'í calendar years are leap if the next Gregorian calendar year is a leap year (February 29th near the beginning of the Gregorian year is always just prior to the last month of the Western Bahá'í calendar year).

Bahá'í calendar days start at local sunset. The calendar employs the traditional 7-day week without interruptions, using Saturday to start the week.

The epoch of the Western Bahá'í calendar was Gregorian March 21, 1844.

For more information about the Bahá'í calendar see the following web sites: <http://www.bahai.us/bahai-calendar> or <http://en.wikipedia.org/wiki/Bahai_calendar>.

For further information about the Bahá'í Faith, see the world site at: <http://www.bahai.org/> or the American site at: <http://www.bahai.us/>.

I am not aware of any internet source for the arithmetic of the Bahá'í calendar, but it is comprehensively covered in Section II "Astronomical Calendars" Chapter 14 "The Bahá'í Calendar" of the book "Calendrical Calculations" by Nachum Dershowitz and Edward M. Reingold, third edition published in 2008 by Cambridge University Press. I will use the mnemonic CC3 to refer to that book.

CC3 gives the arithmetic of the Western Bahá'í calendar, along with what the authors call the "Future" Bahá'í calendar, which employs astronomical algorithms to compute the moment of sunset of the northward equinox in determining the date of Naw-Rúz at any specified locale. Their book also gives the arithmetic for many other calendars, including of course the Gregorian calendar, so Professors Dershowitz & Reingold felt at liberty to call Gregorian calendar functions from their Bahá'í calendar functions.

Click here to see a graph of the northward equinox timing in Haifa relative to the Naw-Rúz of the Western Bahá'í calendar 58KB. Ideally all equinox moments should land between the two red lines. The "zig-zag" pattern, associated with a 2.2-day medium-term "equinox wobble", is caused by the non-uniform distribution of the underlying Gregorian leap year intervals (although most leap years are at 4-year intervals, there are 8-year intervals at the end of 3 out of 4 centuries). The long-term drift of the calendar is obvious, which will cause the equinox to land at progressively earlier moments in the 19th month of the prior Bahá'í calendar year.

Click here to see a graph of the northward equinox timing in Haifa relative to the Naw-Rúz of the Future Bahá'í calendar 50KB, as described in CC3. This astronomic calendar shows the ideal equinox alignment, with the equinox always landing between the two red lines on Naw-Rúz, continuing indefinitely, limited only by the accuracy of the underlying astronomical algorithms. Ideally, fixed arithmetic calendars should reproduce this performance as closely as possible.

On this web page I have adopted the philosophy that to the maximum extent that is technically possible the Bahá'í calendar arithmetic ought to function independently of the Gregorian calendar. The arithmetic of the Western Bahá'í calendar presented herein is independent of the Gregorian calendar, yet it maintains its traditional permanently fixed relationship relative to the Gregorian calendar.

It is true that I have instead made some of the variants herein dependent on Symmetry calendar arithmetic, but that was only for demonstration purposes, by allowing the leap day and leap week variants to be rapidly implemented in my Kalendis calendar calculator with hardly any effort. If the Bahá'í were to ever become seriously interested in a uniformly spread leap day or leap week variant, then it would be easy to implement the appropriate arithmetic as independent functions, finely tuned to any desired meridian.

Overview of Variants of the Bahá'í Calendar

History has shown that a culture is uniquely defined by the calendar that it uses. As such the Western Bahá'í calendar only partially defines a culture, in the sense that it still depends on the Gregorian calendar. In effect it is just a re-labelling of Gregorian calendar dates. Incredibly, in proof of this assertion, the USA Bahá'í observe two additional holidays which have no fixed Bahá'í calendar dates: World Religion Day on the third Sunday in the Gregorian month of January, and Race Unity Day on the second Sunday in the Gregorian month of June, both of which are supported by Kalendis in its implementation of the Gregorian, Symmetry454, and Classic Symmetry calendars, as of version 9.189(910). Kalendis doesn't support either of these events for the Bahá'í calendar or any of the variants documented herein, however, because neither event has a fixed Bahá'í calendar date, nor is there any simple rule to define these events in terms of the Bahá'í calendar.

I feel that the world owes nothing to the Gregorian calendar, and any alternative calendar ought to be fully independent of it. Although I will give herein my own implementation of the arithmetic of the Western Bahá'í calendar, that is only to facilitate interconversions with the other variants offered, and to demonstrate how equivalent arithmetic can be implemented without actually needing Gregorian calendar functions!

Astronomical calendars are unpredictable, in the sense that dates generated depend on the accuracy and implementation of the astronomical algorithms employed. Upgrading to more accurate algorithms can potentially cause any past or future dates to "change". On the other hand, fixed arithmetic calendars are fully predictable, for any past or future date without ambiguity. Astronomical algorithms are of course useful to guide the original choice of fixed arithmetic cycles and constants, but after that are needed only to monitor for calendar drift.

For the variants presented herein, I needed to pick a reference locale for the astronomical algorithms for evaluating alternative fixed arithmetic cycles, so I used the site of the Bahá'í World Centre on Mount Carmel in Haifa, Israel, see <http://www.bahai.org/dir/bwc>.

The reader who is unfamiliar with the changing lengths of the seasons is urged to study my web page "The Lengths of the Seasons" at <http://www.sym454.org/seasons/>, otherwise my preferred fixed arithmetic leap cycle choices won't make much sense.

Position of the Intercalary Days

From a calendarist's point of view, it would be preferable to position any calendar's intercalary days at the end of the year, so that the ordinal day number and ordinal week number of all regular dates of the calendar are the same in every year.

The Bahá'í, however, consider the intercalary days to be holy days, and they observe a sunrise to sunset fast during the contiguous 19 days prior to the coming New Year, so they position the intercalary days ahead of the last 19-day month of the year. Therefore this positioning of the intercalary days is retained in all of the Bahá'í calendar variants presented here.

Fixed Dates — the Rata Die

The computer functions for implementing these Bahá'í calendar variants are designed to convert dates to and from the rata die (ordinal day number, or "fixed date") as described by Dershowitz & Reingold in CC3. The epoch for the rata die is the proleptic Gregorian date Monday, January 1st of the year 1, which was rata die number 1. Such fixed dates serve as a common denominator for interconversion of dates based on any calendar. Relative to that epoch, the Western Bahá'í calendar has an epoch of 673222 days, corresponding to Gregorian 21 March, 1844. To convert a rata die to or from an ordinal day number relative to the Western Bahá'í calendar epoch, simply or subtract or add 673222 days, respectively.

A convenient internet resource for interconverting dates between a wide range of calendars and the rata die is the Calendrica applet of Dershowitz & Reingold at <http://emr.cs.iit.edu/home/reingold/calendar-book/Calendrica.html>. For example, using the arithmetic presented here, any Bahá'í date can be converted to any other calendar supported by the Calendrica applet, via the rata die value for that date, or conversely any date on any other calendar can be converted to a rata die which can then be used with the arithmetic herein to determine the corresponding Bahá'í calendar date (any variant).

Also convenient for demonstrating and verifying implementation of the Bahá'í calendar variants presented here is my freeware program Kalendis, which you can freely download from <http://www.sym454.org/kalendis/>.

Alternative fixed day numbering schemes are easy to implement, merely by assigning an appropriate numeric value to the Bahá'í calendar epoch, the trade-off being the loss of the ability to directly use the fixed day numbers with the Calendrica applet. An obvious choice for Bahá'í calendar purposes is to enumerate the days relative to the Bahá'í epoch itself. For more information see the discussion of fixed day numbering in the Symmetry454 Arithmetic PDF at <http://www.sym454.org/symmetry/>. In addition, Kalendis allows the user to choose from several built-in fixed day numbering epochs, including the epoch of any Bahá'í calendar variant, or it can enumerate days relative to any user-selected arbitrary date in the past or future.

The following table shows examples of a few fixed day numbering epochs with respect to the Western Bahá'í calendar:

Epoch Fixed Date of
Bahá'í Epoch
Fixed Date of
Gregorian Epoch
Comments
Bahá'í epoch 1 -673220 Convenient for Bahá'í calendar work, fixed day numbering relative to the calendar's own epoch.
Gregorian epoch 673222 1 As above, convenient for working in terms of the Reingold / Dershowitz rata die.
Start of 3rd Gregorian millennium -57263 -730484 Fixed day 1 = Gregorian January 1, 2001 AD.
This near-present-era epoch is convenient for working with smaller numbers.
Persian epoch 446327 -226894 Fixed day 1 = Julian March 19, 622 AD.
Windows epoch -20372 -693593 Of some use when working with near present and future dates in Windows applications, where fixed day 1 = Gregorian December 31, 1899 AD, but Windows does not allow negative fixed day numbers, and Windows dates are incorrect prior to March 1, 1900 AD because Windows erroneously considers the Gregorian year 1900 to have been a leap year.

Calendrical calculations make frequent use of dividing a number and keeping only the remainder, for example, dividing the rata die by 7 to determine the weekday. Many programming languages have a MOD operator or function intended for this purpose, but in many languages MOD handles negative or real numbers improperly (the MOD operator of Microsoft Visual Basic is defective on both counts). If you have a defective MOD operator or function, or are not sure, use the following as recommended by Dershowitz & Reingold in CC3:

modulus( x, y ) = x y × floor( x / y )

Not being limited to integer division, the CC3 modulus function also works properly with floating point (real number) parameters provided both the x and the y parameter and the function return value are declared as Double Precision.

If the selected fixed day numbering epoch was not a Monday then calculating the weekday requires a small adjustment, which can be calculated once at the time that the epoch is selected as:

EpochWeekdayAdjust = modulus( GregorianEpoch – 1, 7 )

since the Gregorian epoch is known to have been a Monday. Then the calculation of the weekday number is given by:

FixedToWeekdayNum( FixedDate ) = modulus( floor( FixedDate ) – EpochWeekdayAdjust, 7 )

where Sunday = 0, Monday = 1 ... Saturday = 6. The floor of the FixedDate is taken to discard any fraction of a day (time) component that it contains, and can be omitted if one is working only in terms of dates (integers). Optionally one could add +1 to the result to make Sunday = 1 through Saturday = 7.

Calculation Precision — the Limitations of "Floating Point" Arithmetic

A fixed date that is to represent a day on any calendar is an integer value which corresponds to that date at midnight, and computer program variables used to store and manipulate such fixed dates must be allocated at least 32-bits.

A rata die moment is a date-time value that combines a fixed date integer with a decimal fraction representing the portion of the day that has elapsed (or, for negative moments, prior to the epoch, the portion of the day that has not yet elapsed). All such moments must be stored in variables that support at least Double Precision floating point, because Single Precision is insufficient to resolve specific moments to better than a second when the integer part of the number is relatively large, as is typical of calendar calculations.

I have made every effort to specify coefficients and constants using either exact integers or proper fractions, so that all results can be unambiguously calculated using exact computing engines capable of arbitrary-precision arithmetic, such as Mathematica, or the favorite of Professors Dershowitz & Reingold, the computer programming language "LISP". When a floating point computation does not agree with the exactly calculated result, the exact result must always take precedence.

Some strategies to extend the precision of floating point arithmetic for calendrical calculations include:

Copying Formulae or Statements and Pasting into Other Applications

The formulae presented here have been laid out for readability and clarity. In many cases there will be minor problems if the reader copies a formula from this web page then pastes it directly into a computer programming environment, spreadsheet, or mathematics package. This section outlines how to deal with these minor difficulties:

  1. In most cases instead of a minus sign I use the "N-dash" character "–", or in HTML "&ndash;" because it is easier to see. Almost all calculating environments will require the user to manually replace all N-dash characters with the normal minus sign, which is a simple hyphen like this "-".
  2. I generally avoid using implicit multiplication (operands placed side-by-side without any operator between them). Instead, I use the HTML &times; symbol " × ". Almost all calculating environments will require the user to manually replace all " × ". symbols with an asterisk "*".
  3. In a few places I raise a number or a symbol to a power, for example x2. Most calculating environments will require the user to manually insert an exponentiation symbol such as "^" or "**", for example "x^2" or "x**2".
  4. Where I used numeric scientific notation, for example 1.58 × 10-10, typical programming environments would need such a number in a format like 1.58*10^-10 or simply 1.58e-10 or 1.58E-10.
  5. Fractions can be replaced by floating point constants, but be sure that the values are converted as exactly as possible, always using Double precision or better.
  6. There is no computer programming language that uses exactly the statement or operator syntax that I employ herein, although it is quite similar to Microsoft Visual Basic 6 (VB6). I felt at liberty to change the VB6 syntax to make the statements easier to understand for those that have never used VB6. Don't expect to be able to copy the statements of a function verbatim. Program code won't work until the user makes the minor changes to syntactically adapt it to the target programming environment.
  7. Any text to the right of the straight apostrophe ' symbol is a free text explanatory comment not required in the program code. Nevertheless, in many places I have inserted comments without any such delimiting apostrophe, where I thought the reader would obviously understand that it is free text.
  8. In most cases I haven't specified the type of variable to use for any parameters or return values (eg., boolean, integer, long integer, double, character, string, etc.), because that is system dependent and hopefully obvious from the context.

The All-Important New Year Day (Naw-Rúz)

For all Bahá'í calendar variants the key calendar arithmetic always reduces down to determination of the Naw-Rúz date.

For all variants, it is a leap year only if the next Naw-Rúz is more than 365 days away. For each fixed arithmetic cycle it is also possible to quote a leap rule based on the remainder after dividing the year number by the number of years per cycle, but the year length check method has the advantage that it is simple and applies without modification to any Bahá'í calendar variant.

Furthermore, for all variants, a date is one of the intercalated days if at least 18 × 19 days have elapsed since sunset at the start of Naw-Rúz and if the day is more than 19 days before the next Naw-Rúz. By convention, the Bahá'í calendar intercalated days have a month number equal to zero, even though they are between the 18th and 19th month of the calendar.

A Leap Day Variant With Uniformly Spread Leap Years

The Western Bahá'í calendar has leap year intervals that are non-uniformly spread. Most leap years are at 4-year intervals, but 3 out of 4 centurial years are non-leap, causing 8-year intervals at those points in time. Thus the Gregorian leap rule exaggerates the medium-term "equinox wobble" to a span of 2.2 days, as previously shown in this graph 58KB, whereas a leap day variant based on exactly the same leap cycle of 97 leap years per 400 year cycle but having the leap years at intervals that are as uniformly spread as possible (4- or 5-year intervals) yields a medium-term equinox wobble of only one day, as shown in this graph of the equinox timing for the 97/400 leap day variant 79KB.

In addition, the Gregorian calendar has a long-term equinox drift that is easy to improve upon by choosing a leap cycle that is better suited to the actual length of the mean northward equinoctial year. The Gregorian calendar mean year equals 365+97/400 days, or 5 hours 49 minutes and 12 seconds in excess of 365 days, whereas the present-day mean northward equinoctial year length is 5 hours and 49 minutes in excess of 365 days. In other words, in the present era the Gregorian calendar mean year is about 12 seconds too long per year. The following are a few alternative uniformly-spread leap cycles that minimize medium-term equinox wobble, and those that have a shorter cycle mean year than Gregorian have superior long-term maintenance of equinox alignment:

Cycle Length
(years)
Leap Days
per Cycle
Cycle Mean Year
in excess of 365 days
Comments
400 97 97/400 = 5h 49m 12s Uniformly spread equivalent to the Gregorian calendar, as shown in this graph 79KB.
33 8 8/33 = 5h 49m 5+5/11s Equivalent to the Dee calendar, which inherently has uniformly spread leap years.
524 127 127/524 = 5h 49m 60/131s Only slightly longer than the present-day northward equinoctial mean year, will maintain excellent equinox alignment for the next 3-4 millennia, as shown in this graph 70KB. This cycle contains 6481 synodic or 7005 sidereal lunar months.
293 71 71/293 = 5h 48m 56+152/293s Slightly shorter than the present-day northward equinoctial mean year, but will maintain excellent equinox alignment for an extra half-millennium, as shown in this graph 70KB.
389 94 94/389 = 5h 47m 58+58/389s Too short for the northward equinox mean year, but well suited as an approximation for north solstitial mean year for the next 10 millennia (for example, keeping the first day of the 5th Bahá'í month closely aligned to the average north solstice), as shown in this graph 68KB.

Many other leap day cycles could be employed with reasonable accuracy, but I consider the 71/293 cycle "the winner", at least for the northward equinox. The leap year intervals for the 293-year cycle would be mostly 4-year intervals, with periodic 5-year intervals. The leap year interval pattern can be grouped into sub-cycles of 7 × 4 + 5 = 33 years or 6 × 4 + 5 = 29 years. Each 293-year cycle has one 29-year sub-cycle and eight 33-year sub-cycles. For an analysis of the sub-cycle grouping of a wide range of leap day cycles, see this Excel spreadsheet 32KB, which only includes leap cycles that have a total number of days per cycle that is divisible by 7, to ensure that at least every leap cycle begins on the same weekday and every cycle contains only a whole number of weeks.

The short-term "equinox wobble" of any uniformly-spread leap day variant spans one day, which ideally ought to land on Naw-Rúz. The user of Kalendis can select any leap rule from the experimental Symmetry454 "soup mix", and the Bahá'í calendar leap day variant will synchronize with it. In addition to a wide range of fixed arithmetic cycles, the choices include astronomical rules tied to any actual or mean equinox or solstice, linear approximation rules that use straight line segments to approximate the astronomical mean years of any equinox or solstice, and others. In each case, the Naw-Rúz of the Bahá'í calendar leap day variant will be on the day that is the floor of the Symmetry454 New Year Moment plus 78+1/3 or 75+1/5 days, depending on whether the leap rule is intended to align Naw-Rúz at the average northward equinox, or to align the start of the 5th Bahá'í month at the north solstice, respectively. The underlying Symmetry arithmetic is fine-tuned to align the average northward equinox at noon at the Prime Meridian, but the fractional part of the offset applied to the Symmetry454 New Year Moment fine tunes the alignment to the meridian of Haifa.

In summary, the structure of the leap day variants is identical to the original Bahá'í calendar, the only difference is the leap rule, which will mainly affect calculation of the date of Naw-Rúz.

For extensive information about solar leap cycles, see my web page "Solar Calendar Leap Rule Studies" at <http://www.sym454.org/leap/>.

A Perpetual Leap Week Variant With Uniformly Spread Leap Years

A perpetual calendar is one that always starts the calendar year on the same weekday. This allows a single hardcopy of the calendar to be reused from year-to-year, and all holidays have permanently fixed weekdays. A leap day calendar can never be a perpetual calendar, because the number of days in a year (365 or 366) is not divisible by 7 and therefore do not contain a whole number of weeks. The answer is to change the calendar structure to employ a leap week. Then non-leap years have 364 days, and leap years 371 days, which have exactly 52 or 53 weeks, respectively.

A leap week variant of the Bahá'í calendar could be implemented by having 3 intercalated days in non-leap years, or 10 intercalated days in leap years. The leap year intervals, if as uniformly spread as possible, would most commonly be at 6-year intervals, with less common 5-year intervals also occurring. There are fewer leap week cycles possible than the number of leap day cycles that are possible, because the number of years in the cycle is constrained such that the total number of days in the cycle is divisible by 7.

There is an exact leap week equivalent to "the winner" 293-year leap cycle discussed above, because the number of days per 293-year cycle is divisible by 7. The 293-year leap week variant has 52 leap weeks per cycle, and the average interval between leap weeks is exactly 294 weeks. The leap year interval pattern has groups of 6+6+5=17 years and 6+5=11 years, which further group into sub-cycles of 3 × 17 + 11 = 62-year sub-cycles and 2 × 17 + 11 = 45-year sub-cycles, the full 293-year cycle being composed of four 62-year sub-cycles plus one 45-year sub-cycle. For an analysis of the sub-cycle grouping of a wide range of leap week cycles, see this Excel spreadsheet 44KB.

I have fully documented the leap week calendar arithmetic for the Symmetry454 calendar, see <http://www.sym454.org/symmetry/>. Notice that the 52/293 leap cycle is its preferred cycle too! The leap week variant of the Bahá'í calendar is compatible with any leap cycle from the Symmetry/Kalendis "soup mix". In addition to a wide range of fixed arithmetic cycles, the choices include astronomical rules tied to any actual or mean equinox or solstice, linear approximation rules that use straight lines to approximate the astronomical mean years of any equinox or solstice, and others.

The short-term "equinox wobble" of any uniformly-spread leap week variant spans 7 days, the average of which ideally ought to land at noon on Naw-Rúz. With ideal alignment the equinox could land as early as the 17th day of the last month of the prior Bahá'í year, or as late as the 4th day of the first month of the present Bahá'í year. The underlying Symmetry arithmetic, however, is fine-tuned to align the average northward equinox at noon at the Prime Meridian. Therefore a fractional NewYearOffset is employed to fine-tune the Bahá'í leap week variants to the meridian of Haifa. For leap rules intended to align Naw-Rúz with the average northward equinox, the leap week variant takes the Naw-Rúz date for a given Bahá'í era year as the Saturday that is closest to 78+6/7 days after the Sym454 New Year Moment. For leap rules intended to align the start of the 5th Bahá'í month with the average north solstice, the leap week variant takes the Naw-Rúz date for a given Bahá'í era year as the Saturday that is closest to 75+5/7 days after the Sym454 New Year Moment. The Bahá'í leap week variants are unaffected by the user's choice of "Start On" weekday in the Symmetry454 window of Kalendis — they always start the calendar year on Saturday.

This chart depicts the almost ideal average equinox alignment that would be obtained by using the Leap Week variant with the astronomical "NE79" Symmetry leap rule. 51KB. The best alternative simple fixed arithmetic cycles with uniformly spread leap year intervals are tabulated below:

Cycle Length
(years)
Leap Weeks
per Cycle
Cycle Mean Year
in excess of 365 days
Comments
524 93 127/524 = 5h 49m 60/131s Only slightly longer than the present-day northward equinoctial mean year, will maintain excellent average equinox alignment for the next 3-4 millennia, as shown in this graph 63KB. This cycle contains 6481 synodic or 7005 sidereal lunar months.
293 52 71/293 = 5h 48m 56+152/293s Slightly shorter than the present-day northward equinoctial mean year, but will maintain excellent average equinox alignment for an extra 500 years, as shown in this graph 63KB.
389 69 94/389 = 5h 47m 58+58/389s Too short for the northward equinox mean year, but well suited as an approximation for north solstitial mean year for the next 10 millennia (for example, keeping the first day of the 5th Bahá'í month closely aligned to the average north solstice), as shown in this graph 68KB.
327 58 79/327 = 5h 47m 53+43/109s Even shorter mean year, but also well suited as an approximation for the north solstitial mean year for the next 10 millennia.

The user of Kalendis can select any leap rule from the experimental Symmetry454 "soup mix", and then the Bahá'í calendar leap week variant will start its calendar year on the Saturday that is closest to the corresponding Symmetry454 New Year Moment. In addition to a wide range of fixed arithmetic cycles, the leap rule choices include astronomical rules tied to any actual or mean equinox or solstice, linear approximation rules that use straight lines to approximate the astronomical mean years of any equinox or solstice, and others. In each case, the Bahá'í calendar leap week variant will start its calendar year a certain number of days after the Symmetry454 New Year Moment.

For extensive information about solar leap cycles, especially leap week cycles, see my web page "Solar Calendar Leap Rule Studies" at <http://www.sym454.org/leap/>.

A Leap Month Variant With Uniformly Spread Leap Years

Rather than employing a small number of intercalated days outside of any month, it occurred to me that one could make a leap month variant of the Bahá'í calendar, which would have exactly 19 months = 361 days in regular years, but in leap years would have a leap month = 361+19=380 days. If we say that the leap month is represented by 19 intercalated days (month "zero") between the 18th and 19th months, then non-leap years have no intercalated days, and leap years have a complete 19-day intercalated month.

In English, the leap month could be called "Leap Month", but in Persian, the native language of the Bahá'í calendar, the suggested term is Mah Kabie-Seh, which literally means "month outside of the usual sequence".

I suspect that the Friends of the Bahá'í Faith may not be too impressed with this variant, because in the majority of years it eliminates intercalated days that are ritually important to them. This variant is, however, my personal favorite as a calendarist, and is the primary reason that this entire web page was created, because it ensures that all days of all years are contained within unbroken 19-day months.

Any candidate Bahá'í calendar leap month cycle must have a total number of days that is divisible by 19, and preferably the total number of days in the cycle should also be divisible by 7 so that each cycle (not year) always starts on the same weekday. These constraints significantly limit the possible cycle choices:

Cycle Length
(years)
Leap Months
per Cycle
Cycle Mean Year
in excess of 365 days
Comments
7600 1697 97/400 = 5h 49m 12s Uniformly spread leap month calendar with mean year exactly equal to that of the Gregorian calendar (note that 7600 years = 19 × 400 years).
627 140 8/33 = 5h 49m 5+5/11s Mean year equivalent to the Dee calendar = 19 × 33-year Dee leap cycle (but 229007 days per cycle is not divisible by 7).
524 117 127/524 = 5h 49m 60/131s Mean year about the same as the present-day northward equinoctial mean year, and will maintain excellent northward equinox alignment for about 5 millennia, as shown in this graph 63KB. This cycle contains 6481 synodic or 7005 sidereal lunar months.
5567 1243 71/293 = 5h 48m 56+152/293s Mean year is slightly shorter than the present-day northward equinoctial mean year, but will maintain excellent average equinox alignment for an extra 500 years, just like the 293-year leap day and leap week cycles discussed above (note that 5567 years = 19 × 293 years).
851 190 206/851 = 5h 48m 34+586/851s Intermediate between the 117/524 and the 73/327 leap cycles, but will maintain quite good northward equinox alignment for about 8 millennia, as shown in this graph 69KB.
7391 1650 94/389 = 5h 47m 58+58/389s Too short for the northward equinox mean year, but well suited as an approximation for north solstitial mean year for the next 10 millennia, just like the 389-year leap day and leap week cycles above (note that 7391 years = 19 × 389 years).
327 73 79/327 = 5h 47m 53+43/109s Too short for the northward equinox mean year, but nicely suited for the present era north solstitial mean year, for example to keep the first day of the 5th Bahá'í month closely aligned to the north solstice for perhaps the next 12 millennia 58KB.

Cycle lengths in excess of 1000 years might be considered inconveniently long, but leap month calendars can require such long cycles for desired accuracy. A widely-used precedent is the Gregorian Easter computus, which has 2,099,183 leap months in 5,700,000 years!

The leap year interval pattern for the 524-cycle has groups of 5+4=9 years and 5+4+4=13 years, which further group into sub-cycles of 11 × 9 + 13 = 112-year sub-cycles and 10 × 9 + 13 = 103-year sub-cycles, the full 524-year cycle being composed of one 112-year sub-cycle plus four 103-year sub-cycles.

Several additional leap month cycles are suitable if there is no requirement for the number of days per cycle to be divisible by 7.

I used the method of continued fractions to discover a wide range of potential 19-day leap month cycles. In addition, via internet email, K.E.V. (Karl) Palmen of the United Kingdom <http://www.hermetic.ch/cal_stud/palmen/index.html>, an expert in calendars in general but with a particular interest in lunar and leap month calendars, corresponded heavily with me in discovering these cycles and characterizing their leap year interval groupings and sub-cycles. For the full range of 19-day leap month cycle details, and an analysis of the leap year interval sub-cycle groupings, see this Excel spreadsheet 140KB. (Karl also made important contributions to the Symmetry454 calendar arithmetic that underlies the leap day and leap week variants proposed herein.)

For further information about continued fractions, see <http://mathworld.wolfram.com/ContinuedFraction.html>. The following are continued fraction calculators that anybody can freely use on-line:

This one displays the full continued fraction graphically:
<http://www.hostsrv.com/webmaa/app1/MSP/webm1010/continuedfraction>

This one shows intermediate values used to compute the continued fraction, and offers a full explanation about continued fraction:
<http://www.mcs.surrey.ac.uk/Personal/R.Knott/Fibonacci/cfCALC.html>

The short-term "equinox wobble" of any uniformly-spread Bahá'í leap month variant spans 19 days, the average of which ideally ought to land at noon on Naw-Rúz. With ideal alignment the equinox could land as early as the 11th day of the last month of the prior Bahá'í year, or as late as the 10th day of the first month of the present Bahá'í year.

The Bahá'í Calendar Mode

The calendar arithmetic documented herein supports multiple modes, allowing it to carry out calendar calculations and interconversions for any of the variants proposed here, depending on the value of the Mode parameter passed to its functions. The Mode parameter need only be passed to functions that actually handle the modes differently.

The values of Mode are based the following enumeration:

Western = 1
Future
= 2 ' (implementation not fully discussed here, CC3 arithmetic is compatible)
LeapDay = 3
LeapWeek
= 4
LeapMonth
= 5

The fixed arithmetic LeapDay, LeapWeek, and LeapMonth variant modes require further specification with regard to the selected leap cycle:

YearsPerCycle ' number of years per leap cycle

LeapYearsPerCycle ' number of leap years in each leap cycle

' Total number of days in a full cycle (preferably divisible by 19 and by 7 without a remainder)
' (for leap month variants must be divisible by 19 without a remainder)
Leap Month: DaysPerCycle = YearsPerCycle × 361 + LeapYearsPerCycle × 19
Leap Week: DaysPerCycle = YearsPerCycle × 364 + LeapYearsPerCycle × 7
Leap Day: DaysPerCycle = YearsPerCycle × 365 + LeapYearsPerCycle

' Total number of months in a full cycle (for a valid leap month cycle, must be an integer)
MonthsPerCycle = DaysPerCycle / 19

' Numerator of fractional part of day in excess of 365 days (years per cycle is the denominator)
LeapDayEquivalent = DaysPerCycleYearsPerCycle × 365

' Decimal fractional part of day in excess of 365 days
LeapDayEquivalentFraction = LeapDayEquivalent / YearsPerCycle

' The mean year of the cycle (the LeapDayEquivalentFraction is separate for more significant figures in floating point calculations)
CycleMeanYear = 365 + LeapDayEquivalentFraction

The Western mode has YearsPerCycle = 400, LeapYearsPerCycle = 97, and the rest is calculated as above (for example, CycleMeanYear = 365.2425).

In Kalendis, when the user selects a Bahá'í calendar variant leap month, week, day or Western leap rule, the parameters outlined above are immediately calculated as given above, and stored for future reference until changed. The leap day and leap week details can be obtained from the Symmetry454 window, depending on which leap rule is selected by the user at the bottom of the Symmetry454 window.

The Future mode requires specification of the reference locale for the northward equinox, for which the user of Kalendis can optionally select Haifa, Israel (at sea level or on Mount Carmel), or Tehran, Iran, or Wilmette, USA (site of a large American Bahá'í Temple near Chicago). For coordinates and elevation see the information displayed by Kalendis when those locales are picked.

In the implementation suggested herein, I have shown Mode as an explicit parameter that is passed to each function that may require it, but the programmer may prefer to declare Mode as a global variable instead. This will probably be more efficient, in that it avoids passing Mode to functions that use it only pass it to other functions. However, use of a global variable may make program code harder to understand, and there is a risk that one will forget to set the appropriate Mode. Passing the Mode explicitly is more convenient when rapidly switching modes, for example in comparative evaluations or date conversion operations. In addition, this strategy avoids the need for a programming environment that supports global variable declarations.

Constants

The following constants will be used in the functions presented below, and are defined here:

GregorianEPOCH = 1 ' rata die fixed date of the Gregorian calendar epoch on January 1, 1 AD.

BahaiEPOCH = 673222 ' rata die fixed date of the Bahá'í calendar epoch on Gregorian 21 March, 1844

Information about alternative epoch values for working in terms of fixed day numbering schemes other than the rata die was given above in the introductory discussion of fixed day numbering.

BahaiEpochYear = 1844 ' Gregorian year number of the Bahá'í calendar epoch (Bahá'í era year number 1)

MeanNEyear = 365+71/293 ' approximate value for the mean northward equinoctial year length

DaysBeforeIntercalary = 18 × 19 ' number of days prior to the intercalary days, always the same in all variants

In addition, the numbers 19, 361, and 365 are used frequently, so depending on the programming environment, it may be worthwhile to declare constant symbols for them to be used instead of the numbers.

The arithmetic presented herein assumes that the Bahá'í era year prior to the epoch was year number zero, and prior historical years were negative Bahá'í year numbers of Major = 0. The Major number is considered negative 361 years earlier.

The YearToElapsedMonths and ElapsedMonthsToFixed Functions

These functions are used only for the experimental uniformly spread leap month Bahá'í calendar variant. They are used together to find the starting date for any given Bahá'í era year.

Given a Bahá'í era year number, the YearToElapsedMonths function simply calculates how many months will have elapsed from the Bahá'í calendar epoch until the start of the specified Bahá'í era year, which depends on the number of years in the leap cycle, and the number of leap years per cycle:

YearToElapsedMonths( BEyear ) = 19 × BEyear – 19 + quotient( LeapYearsPerCycle × BEyear, YearsPerCycle )

For any known number of elapsed months, it is a trivial matter to determine the fixed date of the start of the following month, by simply multiplying the number of months by 19 and adding in the fixed date of the calendar epoch. This strategy will be employed in the Naw-Rúz function to find the New Year Day. The leap month variants use an "adjusted" calendar epoch to optimize the alignment of the average northward equinox relative to the date of Naw-Rúz:

ElapsedMonthsToFixed( ElapsedMonths ) = AdjustedBahaiEPOCH + ElapsedMonths × 19

where AdjustedBahaiEPOCH is a small positive offset relative to the standard BahaiEPOCH that was defined in the constants section above:

Years Per Cycle Leap Months per Cycle Epoch Adjustment Gregorian Date of 1.1.1.1.1
524 117 +5 days March 26, 1844
851 190 +6 days March 27, 1844
327 73 +3 days March 24, 1844

In each case I determined the proposed Epoch Adjustment by evaluating the timing of the northward equinox relative to the date of Naw-Rúz over the first 8000 years of the Bahá'í era, referred to the locale on Mount Carmel in Haifa, Israel.

The Naw-Rúz Function

This function determines the rata die fixed date of Naw-Rúz using the specified Mode (Bahá'í calendar variant) and the specified Bahá'í era year. This is the only calendar arithmetic function that truly cares which variant is being used. All other functions have identical arithmetic for all variants. The calling syntax is simply:

ThisNawRuz = NawRuz( Mode, BEyear )

Based on the specified Mode the appropriate variant-specific section of program code is to be executed, but any code for variants that will never be used may be omitted, of course.

SELECT CASE Mode

CASE LeapMonth

RETURN ElapsedMonthsToFixed( YearToElapsedMonths( BEyear ) )

For the LeapWeek variant, take the date of Naw-Rúz as the Saturday that is closest to the NewYearOffset plus the Symmetry New Year Moment, using the standard arithmetic of the SymNewYear function as documented in the Symmetry454 calendar arithmetic. This is accomplished using the standard arithmetic of the SymNewYear function as documented in the Symmetry454 calendar arithmetic, except that the very last step is omitted, returning the New Year Moment instead of the New Year Day. In the expression below, I have added a boolean OnlyTheMoment parameter to signal to the SymNewYear function that it is to skip that last step:

CASE LeapWeek

NewYearOffset = 78+6/7 ' for leap rules intended to align Naw-Rúz with the average northward equinox

( or )

NewYearOffset = 75+5/7 ' to align the start of the 5th Bahá'í month with the average north solstice

NewYearMoment = NewYearOffset + SymNewYear( BEyear + BahaiEpochYear – 1, OnlyTheMoment )

' get ready to find the nearest Saturday, like CC3 k-day-nearest function
NewYearDay = floor( NewYearMoment ) + 3

' finally return the nearest Saturday (6 = number for Saturday, 7 = days per week)
RETURN NewYearDay – modulus( NewYearDay – 6, 7 )

Kalendis also allows the user to pick other leap rules intended to align relative to the southward equinox, south solstice, Besselian New Year moment, and others. For all of these it will default to using a NewYearOffset of 78+6/7 days for Bahá'í week variants, but the optimal offset is undefined.

The LeapDay variant is almost the same as the LeapWeek variant, except that it takes the date of Naw-Rúz as a certain number of days after the floor of the Symmetry New Year Moment. This is accomplished using the standard arithmetic of the SymNewYear function as documented in the Symmetry454 calendar arithmetic, except that the very last step is omitted, returning the New Year Moment instead of the New Year Day. In the expression below, I have added a boolean OnlyTheMoment parameter to signal to the SymNewYear function that it is to skip that last step:

CASE LeapDay

NewYearOffset = 78+1/3 ' for leap rules intended to align Naw-Rúz with the average northward equinox

( or )

NewYearOffset = 75+1/5 ' to align the start of the 5th Bahá'í month with the average north solstice

RETURN NewYearOffset + floor( SymNewYear( BEyear + BahaiEpochYear – 1), OnlyTheMoment )

Kalendis also allows the user to pick other leap rules intended to align relative to the southward equinox, south solstice, Besselian New Year moment, and others. For all of these it will default to using a NewYearOffset of 78+1/3 days for Bahá'í leap day variants, but the optimal offset is undefined.

The Western Bahá'í calendar always starts the year on Gregorian March 21st. The arithmetic for this has already been documented in CC3, but here I present an alternative method that avoids dependency on explicit Gregorian calendar functions. We compute the number of days that have elapsed from Western Bahai epoch on Gregorian March, 21, 1844 until the Naw-Rúz of the specified Bahá'í era year. This works by calculating the number of days until the end of the corresponding Gregorian year (365 days for each elapsed year since the Gregorian epoch, plus 4 days for every 4th year, minus 1 day for each elapsed centurial non-leap year, plus 1 day for each elapsed quad-centurial leap year), then backing up by 286 days:

CASE Western

gYear = BEyear + BahaiEpochYear – 1

RETURN GregorianEPOCH + gYear × 365 + floor(gYear/4) – floor(gYear/100) + floor(gYear/400) – 286

As written in CC3, the Future Bahá'í arithmetic needs a fixed date that is somewhere in the target year, then the arithmetic uses an astronomical search to find the closest prior Future Bahá'í Naw-Rúz. We use the fixed date of the Bahá'í calendar epoch, add in a multiple of the mean northward equinoctial year length, then add a few more days (I arbitrarily chose to use 30 days) to be sure that we land within the correct year before calling the astronomical search function:

CASE Future ' this requires the CC3 future-bahai-new-year-on-or-before function

RETURN FutureBahaiNewYearOnOrBefore( BahaiEPOCH + ( BEyear – 1 ) × MeanNEyear + 30 )

END SELECT ' end of Mode selection of Naw-Rúz calculation

This Naw-Rúz function is called by the FixedToBahai, BahaiToFixed, and isLeapYear functions.

The isLeapYear Function

This function returns TRUE if the specified Bahá'í era year is a leap year, depending on the specified Mode (Bahá'í calendar variant).

The calendar arithmetic itself has no need for this function. The isLeapYear function is provided simply because most people expect it to exist, and to facilitate generating lists of leap years. The function works by checking the length of the year, calculated by subtracting the fixed date of Naw-Rúz from the fixed date of the next Naw-Rúz. If the difference is more than 365 days then it is a leap year. This year length check method is generically compatible with any Bahá'í calendar variant using any leap rule:

isLeapYear( BEyear ) = NawRuz( Mode, BEyear + 1 ) – NawRuz( Mode, BEyear ) > 365

For the fixed arithmetic leap cycle leap rules it is also possible to use a simple divide-then-check-remainder expression to determine leap status. For the leap week variants see the Symmetry454 Arithmetic and Symmetry454 Leap Week documentation. For the leap month variants one could define a hasLeapMonth function as follows:

hasLeapMonth( BEyear ) = modulus( LeapYearsPerCycle × ( BEyear + 1 ), YearsPerCycle ) < LeapYearsPerCycle

When generating a list of leap years, the program can save time by skipping years that can't possibly be leap years. For leap day or leap month variants the leap year intervals are either 4 or 5 years, so whenever a leap year is found, the program can skip 3 years. For leap week variants the leap year intervals are either 6 or 5 years, so whenever a leap year is found, the program can skip 4 years.

The IntercalaryDays Function

This function returns is similar to the isLeapYear function above, except that instead of returning a boolean TRUE/FALSE, it returns the count of intercalary days in the specified Bahá'í era year, according to the specified Mode (Bahá'í calendar variant). The possible return values depend on the type of calendar variant:

Variant Regular Year Leap Year
Western, Future, Leap Day 4 5
Leap Week 3 10
Leap Month 0 19

The function simply calculates the year length, then subtracts the number of days in the first 18 months and also subtracts the 19 days of the last (19th) month:

IntercalaryDays( Mode, BEyear ) = NawRuz( Mode, BEyear + 1) – NawRuz( Mode, BEyear ) – DaysBeforeIntercalary – 19

This function is not needed for ordinary operations, but it is useful when generating monthly calendar views for display or printout, so that the program will know how many intercalary days to show, if any. It is also useful for random date validation, allowing the program to randomly pick valid intercalary day numbers during automated verification of calendar functions, by ensuring that a randomly generated intercalary day number is not out-of-range.

The FixedToBahai Function

Given a rata die fixed date, this function finds the corresponding Bahá'í calendar date using the specified variant Mode, returning fixed dates for this Naw-Rúz and the next Naw-Rúz, the Bahá'í era year number, the major, cycle, year number within the cycle, the month number (1-19, or zero for any of the intercalated days), and the day number within the month (1-19). As this function returns multiple values, and the way to implement that will depend on the programming environment, I will only show how those values are computed, not the calling syntax nor how the results are returned. They could, for example, be returned by changing the values of global variables, or the values of multiple parameters passed by reference (this would be cumbersome because of the large number of parameters involved), or by passing a Bahá'í date record by reference, or by setting properties of a Bahá'í date object.

If the given fixed date might be a moment (possibly having a fractional part representing the time-of-day) then take the floor of it to truncate the fraction before proceeding.

IF Mode = Future THEN

ThisNawRuz = FutureBahaiNewYearOnOrBefore( FixedDate ) ' this is a CC3 function

' round to nearest year number, plus one because Bahá'í year at epoch was year 1

BEyear = 1 + floor( 0.5 + ( ThisNawRuzBahaiEPOCH ) / MeanNEyear )

' jump ahead by the length of a leap year to be sure that we pass a fixed date that is in the next Future Bahai year

NextNawRuz = FutureBahaiNewYearOnOrBefore( ThisNawRuz + 366 )

ELSE

IF Mode = LeapMonth OR Mode = Western THEN

' Leap month cycles and Western Bahá'í calendar require a non-zero cycle mean year, which is used to estimate the Bahá'í era year:

BEyear = 1 + floor( ( FixedDateBahaiEPOCH ) / CycleMeanYear )

Leap day and leap week variants are synchronized with Symmetry, so we will estimate the year number using Symmetry arithmetic. One could employ the same strategy for leap day or leap week variants as we did above for the leap month variants, using for example the selected Symmetry leap rule cycle mean year, but that would work only for those Symmetry cycles that have fixed arithmetic cycles. Instead we let the Symmetry arithmetic estimate the year number for us, so it can handle any of the astronomical, mean astronomical, or linear approximation leap rules in addition to any of the fixed arithmetic cycles.

The Symmetry New Year Day is about 80 days prior to the Bahá'í Naw-Rúz, so to enhance the chance of getting the correct Bahá'í era year number on the first try, we will subtract an Offset value, optimized for the variant type. If we didn't subtract such an Offset value then the year number would initially be one year number too low for about 25% of random dates, whenever the date lands between the Symmetry New Year Day and the Bahá'í Naw-Rúz. By using an Offset = 79 for Mode = LeapWeek the correct year number will always be obtained on the first try. By using an Offset = 81 for Mode = LeapDay the correct year number will be obtained on the first try for more than 99% of random dates, and the year number will never initially be too far into the future.

We will get the Bahá'í year and New Year Day (synchronized with Symmetry), adjusted for Bahai year at epoch, but we don't care about the Symmetry New Year Day itself because that is for a leap week calendar, yet we pass it as a dummy because it is required:

ELSE

IF Mode = LeapWeek THEN Offset = 79 ELSE Offset = 81

BEyear = FixedToSymYear( FixedDateOffset, SymNewYearDay) – BahaiEpochYear + 1

END IF

Now for all Modes we check if our estimated Bahá'í era year number is correct, going back or forward by one year if necessary:

ThisNawRuz = NawRuz( Mode, BEyear )

' If the fixed date is before this Naw-Rúz then our year number is too far into the future:

IF FixedDate < ThisNawRuz THEN

The fixed date is prior to our initial estimate for Naw-Rúz, so go back to prior Bahá'í era year. By means of random date validation, I found that execution never executes the next 3 lines for the Western, LeapDay, or LeapWeek variants, and LeapMonth variants execute them only rarely (<0.15% of dates).

NextNawRuz = ThisNawRuz ' remember our next Naw-Rúz date

BEyear = BEyear – 1 ' go back to previous Bahá'í era year

ThisNawRuz = NawRuz( Mode, BEyear ) ' revise our Naw-Rúz date

Otherwise, we probably have the right year, but we also need the next Naw-Rúz fixed date, and after we get that if we find that the fixed date is beyond it then we need to jump ahead to the next Bahá'í era year. There is no need to search iteratively backward or forward looking for the correct Bahá'í era year number, because it is always within plus or minus one year of the initial estimate.

ELSE ' FixedDate is not less than ThisNawRuz...

NextNawRuz = NawRuz( Mode, BEyear + 1 )

' before assuming all is well, check if the given fixed date is on or beyond the next Naw-Rúz

IF FixedDate >= NextNawRuz THEN

The fixed date is in next year, so we have to skip one year into the future. In random date validation, this condition is never invoked for the LeapWeek variant, is rarely executed by the Western Bahá'í arithmetic (<0.2% of dates), and is uncommonly executed by the LeapDay (<1% of dates) and LeapMonth variants (<1.7% of dates).

ThisNawRuz = NextNawRuz ' use the next Naw-Rúz date that we already have

BEyear = BEyear + 1 ' go forward to the next Bahai year

NextNawRuz = NawRuz( Mode, BEyear + 1 ) ' revise our next Naw-Rúz date

END IF ' fixed date on or beyond next Naw-Rúz

END IF ' fixed date before this Naw-Rúz

END IF ' Future Bahá'í

At this point we are sure of the fixed date for this Naw-Rúz and the next, as well as the Bahá'í era year number. We can optionally use them to generically determine the leap status of the year, based on year length check (leap years of all variants have more than 365 days in the year), although the calendar arithmetic itself has no further need for this information:

isLeap = NextNawRuzThisNawRuz > 365

The Bahá'í era year number is one-based (first year at the epoch was year number one, not zero), but for calculating the separated major/cycle/year we need to convert it to a zero-based year number, which we will store in a temporary variable:

ZeroBasedYears = BEyear – 1

MajorNum = quotient( ZeroBasedYears, 361 ) + 1

CycleNum = quotient( modulus( ZeroBasedYears, 361 ), 19 ) + 1 ' cycle number within the major

YearNum = modulus( ZeroBasedYears, 19 ) + 1 ' year number within the cycle

Calculate the prior days that have elapsed within this year:

ElapsedDays = FixedDateThisNawRuz

Based on the number of elapsed days, and their offset relative to the next Naw-Rúz, determine the Bahá'í month and how many days are prior to the start of that month:

IF ElapsedDays < DaysBeforeIntercalary THEN

' for months 1 through 18, prior to the intercalary days, directly calculate the month number

MonthNum = 1 + quotient( ElapsedDays, 19 )

DaysBeforeMonth = 19 × MonthNum – 19

Otherwise the fixed date is either in the intercalated days or the last (19th) month. The last month always starts 19 days before the next Naw-Rúz, whose fixed date we already know, so we can calculate how many days are before the 19th month. If the elapsed days equal or exceed the number of days prior to the 19th month, then our fixed date is in the 19th month, otherwise it is in the intercalary days:

ELSE

DaysBeforeMonth = NextNawRuz – 19 – ThisNawRuz

IF ElapsedDays >= DaysBeforeMonth THEN

' fixed date is in the 19th month, and we have the correct DaysBeforeMonth count

MonthNum = 19

ELSE

' fixed date is in the intercalary days, which are conventionally month number "zero", a null month

MonthNum = 0

' reset DaysBeforeMonth to the count of days prior to the start of the intercalary days

DaysBeforeMonth = DaysBeforeIntercalary

END IF

END IF

We are almost finished! All that is left to do is to calculate the day number within the month, which is simply:

DayNum = ElapsedDaysDaysBeforeMonth + 1

The BahaiToFixed Function

Given the major number, cycle number within the major and year number within the cycle, relative to the Bahá'í calendar epoch, as well as the month number and day number within the month, the BahaiToFixed function returns the rata die fixed date. If desired, the Bahá'í era year number can be used instead of the year number iwthin the cycle, by setting major=1 and cycle=1. This function is identical for all variants. Any variant-specific processing differences are handled within the NawRuz function that it calls. Therefore the BahaiToFixed function needs the Mode parameter just to pass it to the NawRuz function. The calling syntax is:

FixedDate = BahaiToFixed( Mode, MajorNum, CycleNum, YearNum, MonthNum, DayNum)

The first step is converting the major, cycle, and year number within the cycle to a Bahá'í era year number. After that the fixed date of Naw-Rúz is easily determined and thereafter the logic is trivial:

BEyear = ( MajorNum – 1 ) × 361 + ( CycleNum – 1 ) × 19 + YearNum

However, the above can be simplified to the following:

BEyear = MajorNum × 361 + CycleNum × 19 + YearNum – 380

As soon as we know the Bahá'í era year number, it is easy to find the start-of-year fixed date:

ThisNawRuz = NawRuz( Mode, BEyear )

Thereafter we just need to know how many days there are prior to the given month:

IF MonthNum < 19 THEN ' this is month 0 to 18

IF MonthNum = 0 THEN ' intercalary days

DaysBeforeMonth = DaysBeforeIntercalary

ELSE ' for months 1 to 18 just take 19 days for each prior elapsed month

DaysBeforeMonth = 19 × MonthNum – 19

END IF

ELSE ' this is the 19th month (always starts 19 days before next Naw Ruz), calculate how many days before it

DaysBeforeMonth = NawRuz( Mode, BEyear + 1) – 19 – ThisNawRuz

END IF

Finally the last step combines together the fixed date of Naw-Rúz plus the number of days prior to the given month plus the day number within the given month, less one day:

RETURN ThisNawRuz + DaysBeforeMonth + DayNum – 1

Once the fixed date is obtained, it can be converted to any other variant date using the FixedToBahai function, or it can be used in calendrical calculations (such as finding the difference between two dates, in days), or to find some other date a certain number of days in the past or future (use FixedToBahai to find out what that date was or will be after subtracting or adding the desired number of days), or it can be converted to any other calendar using CC3 calendrical functions or the on-line Calendrica applet of Dershowitz & Reingold at <http://emr.cs.iit.edu/home/reingold/calendar-book/Calendrica.html>.

Converting Bahá'í Dates

To convert any Bahá'í calendar variant date to any other Bahá'í calendar variant date, use the BahaiToFixed function in the desired variant Mode to convert the Bahá'í date to a rata die fixed date, then use FixedToBahai in the other desired variant Mode to convert the fixed date to Bahá'í calendar date in the other variant.

To convert any other calendar to a Bahá'í calendar variant date, first convert the other calendar date to a rata die fixed date (if you don't have your own way to do this, simply use the on-line Calendrica applet of Dershowitz & Reingold at <http://emr.cs.iit.edu/home/reingold/calendar-book/Calendrica.html>), then use FixedToBahai in the desired variant Mode to convert the fixed date to a Bahá'í date in the desired variant.

To convert any Bahá'í calendar variant date to another non-Bahá'í calendar, use BahaiToFixed in the appropriate Mode to convert the Bahá'í date to a rata die fixed date, then use your own software or the Calendrica applet to convert the fixed date to the desired non-Bahá'í calendar date.

Checking if a Date is Valid

To check if any Bahá'í calendar date exists in any desired variant, which may be especially useful to know for the intercalary days, or if anybody inadvertently attempts to use a day number within a month outside of the range 1 to 19, it is simple to use the procedure recommended by Dershowitz & Reingold in CC3: convert the calendar date to a fixed date, then convert the fixed date back to the same calendar — if the returned date is the same as the original date, then the original date exists. Here is an example of such a BahaiToFixedFixedToBahai procedure:

FixedDate = BahaiToFixed( Mode, MajorNum1, CycleNum1, YearNum1, Month1, Day1 )

Then use FixedToBahai( Mode, FixedDate ) to convert back to MajorNum2, CycleNum2, YearNum2, Month2, Day2, and finally verify that we got back what we started with:

DateExists = ( MajorNum1 = MajorNum2 ) AND ( CycleNum1 = CycleNum2 )
AND ( YearNum1 = YearNum2 ) AND ( Month1 = Month2 ) AND ( Day1 = Day2 )

One could simplify the above if working only with Bahá'í era year numbers instead of the fully separated major/cycle/year, by passing MajorNum=1 and CycleNum=1 to BahaiToFixed:

FixedDate = BahaiToFixed( Mode, 1, 1, BEyearNum1, Month1, Day1 )

Then use FixedToBahai( Mode, FixedDate ) to convert back to BEyear2, Month2, Day2, and finally verify that we got back what we started with:

DateExists = ( BEyear1 = BEyear2 ) AND ( Month1 = Month2 ) AND ( Day1 = Day2 )

The boolean variable DateExists is set to TRUE if the original date is a valid Bahá'í calendar date in the specified Mode, or FALSE otherwise.

Random Date Validation

After implementing any calendar arithmetic functions, it is a good idea to automatically validate thousands of dates to ensure that the program never malfunctions. One way to do so is to randomly generate calendar dates, convert them to fixed dates, then back to calendar dates, checking as above that the date returned matches the originally generated date.

When randomly generating dates for any Bahá'í calendar variant, the major can be any integer from negative numbers to zero or any positive number, and the cycle and year number within the cycle can be any integer from 1 to 19. The month number can be any integer from 0 to 19. When month number zero is picked the IntercalaryDays function should be called to get the intercalary day count for that year, after calculating the Bahá'í era year number as was shown in the BahaiToFixed function. For leap month variants, only leap years have intercalary days, so the count is zero for non-leap years, in which case the program should randomly pick another month from 1 to 19 before randomly picking the day number 1 to 19 within that month.

I have used random validation to verify the operation of each of the variants documented herein, for tens of thousands of randomly generated dates for each variant.


Updated 168/00/04 BE (Western Bahá'í) = 168/19/04 BE (117/524 Leap Month) = Feb 31, 2012 (Symmetry454) = Feb 29, 2012 (Symmetry010) = Feb 29, 2012 (Gregorian)