(* Calendrica 1.0b1 *) (** ;;;; The Functions (code, comments, and definitions) contained in this ;;;; file (the "Program") were written by Nachum Dershowitz and Edward ;;;; M. Reingold (the "Authors"), who retain all rights to them except ;;;; as granted in the License and subject to the warranty and ;;;; liability limitations below. These Functions are explained in ;;;; the Authors' book, "Calendrical Calculations" (Cambridge ;;;; University Press, 1997), and are subject to an international ;;;; copyright and a Patent Pending on certain functions. ;;;; ;;;; The Authors' public service intent is more liberal than suggested ;;;; by the License below, as are their licensing policies for ;;;; otherwise nonallowed uses such as--without limitation--those in ;;;; commercial, web-site, and large-scale academic contexts. Please ;;;; see the web-site ;;;; ;;;; http://emr.cs.uiuc.edu/~reingold/calendar-book/index.html ;;;; ;;;; for all uses not authorized below; in case there is cause ;;;; for doubt about whether a use you contemplate is authorized, ;;;; please contact the Authors (e-mail: reingold@cs.uiuc.edu). ;;;; For commercial licensing information, contact the authors at ;;;; the Department of Computer Science, 1304 West Springfield ;;;; Avenue, University of Illinois at Urbana-Champaign, Urbana, ;;;; IL 61801-2987, USA. ;;;; ;;;; 1. LICENSE. The Authors grant you a license for personal ;;;; use only. This means that for strictly personal use you may ;;;; copy and use the code, and keep a backup or archival copy ;;;; also. Any other uses, including without limitation, ;;;; allowing the code or its output to be accessed, used, or ;;;; available to others, is not permitted. ;;;; ;;;; 2. WARRANTY. ;;;; ;;;; (a) THE AUTHORS PROVIDE NO WARRANTIES OF ANY KIND, EITHER ;;;; EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITING THE ;;;; GENERALITY OF THE FOREGOING, ANY IMPLIED WARRANTY OF ;;;; MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. ;;;; ;;;; (b) THE AUTHORS SHALL NOT BE LIABLE TO YOU OR ANY THIRD PARTIES ;;;; FOR DAMAGES OF ANY KIND, INCLUDING WITHOUT LIMITATION, ANY LOST ;;;; PROFITS, LOST SAVINGS, OR ANY OTHER INCIDENTAL OR CONSEQUENTIAL ;;;; DAMAGES ARISING OUT OF OR RELATED TO THE USE, INABILITY TO USE, ;;;; OR INACCURACY OF CALCULATIONS, OF THE CODE AND FUNCTIONS ;;;; CONTAINED HEREIN, OR THE BREACH OF ANY EXPRESS OR IMPLIED ;;;; WARRANTY, EVEN IF THE AUTHORS OR PUBLISHER HAVE BEEN ADVISED OF ;;;; THE POSSIBILITY OF THOSE DAMAGES. ;;;; ;;;; (c) The foregoing warranty may give you specific legal ;;;; rights which may vary from state to state in the U.S.A. ;;;; ;;;; 3. LIMITATION OF LICENSEE REMEDIES. You acknowledge and ;;;; agree that your exclusive remedy (in law or in equity), and ;;;; Authors' entire liability with respect to ;;;; the material herein, for any breach of representation or for ;;;; any inaccuracy shall be a refund of the license fee or service ;;;; and handling charge which you paid the Authors, if any. ;;;; ;;;; SOME STATES IN THE U.S.A. DO NOT ALLOW THE EXCLUSION OR ;;;; LIMITATION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES, ;;;; SO THE ABOVE EXCLUSIONS OR LIMITATION MAY NOT APPLY TO YOU. ;;;; 4. DISCLAIMER. Except as expressly set forth above, the Authors: ;;;; ;;;; (a) make no other warranties with respect to the material in ;;;; the Program and expressly disclaim any others; ;;;; ;;;; (b) do not warrant that the material contained in the Program ;;;; will meet your requirements or that their operation shall be ;;;; uninterrupted or error-free; ;;;; ;;;; (c) license this material on an "as is" basis, and the entire ;;;; risk as to the quality, accuracy, and performance of the ;;;; Program is yours, should the code prove defective (except as ;;;; expressly warranted herein). You alone assume the entire cost ;;;; of all necessary corrections. ;;;; ;;;; Sample values for the functions (useful for debugging) are ;;;; given in Appendix C of the book. These sample values are ;;;; not available electronically. ;;;; Last modified 27 May 1997. **) Remove["Calendrica`*"] Remove["Calendrica`Private`*"] BeginPackage["Calendrica`"] (*----------------------------------------------------------------------------*) (*=============================================== Public Usage information ===*) (*----------------------------------------------------------------------------*) (* General Information *) Calendrica::usage = "Calendrica is a package for generalized manipulation and conversion of dates through various modern and historical calendars. It is based on the work of Nachum Dershowitz and Edward M. Reingold in their book _Calendrical Calculations_, published by Cambridge University Press, ISBN 0-521-56474-3. This _Mathematica_ translation was performed by Robert C. McNally ." (* Special Names *) Bogus::usage = "Bogus represents nonexistent dates." Calendars::usage = "Calendars[] returns the set of all supported calendars" (* Arithmetical Calendars *) Map[(Evaluate[#[[1]]]::"usage" = StringJoin[ToString[#[[1]]], " represents the ", #[[2]], " calendar. ", ToString[#[[1]]], "[] returns a list of components in ", #[[3]], " calendar dates. ", ToString[#[[1]]], "[fixedDate] returns the ", #[[3]], " calendar date corresponding to the given fixed date."])&, { {Gregorian, "present civil (Gregorian)", "Gregorian"}, {ISO, "ISO commercial", "ISO"}, {Julian, "old civil (Julian)", "Julian"}, {Coptic, "Coptic", "Coptic"}, {Ethiopic, "Ethiopic", "Ethiopic"}, {Islamic, "Islamic (Moslem)", "Islamic"}, {Persian, "Persian (solar)", "Persian"}, {Bahai, "Baha'i", "Baha'i"}, {Hebrew, "Hebrew (Jewish)", "Hebrew"}, {MayanLongCount, "Mayan long count", "long count"}, {MayanHaab, "Mayan haab", "haab"}, {MayanTzolkin, "Mayan tzolkin", "tzolkin"}, {OldHinduSolar, "old (mean) Hindu (Indian)", "old Hindu solar"}, {OldHinduLunar, "old (mean) Hindu (Indian)", "old Hindu lunar"}, {French, "original form of the French Revolutionary", "French Revolutionary"}, {ModifiedFrench, "modified form of the French Revolutionary", "modified French Revolutionary"}, {Chinese, "Chinese", "Chinese"}, {HinduSolar, "new (true) Hindu (Indian) solar", "new Hindu solar"}, {HinduLunar, "new (true) Hindu (Indian) lunar", "new Hindu lunar"} }] (* Names of standard week days *) DayOfWeekNames[] = {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday} Map[(Evaluate[#]::"usage" = StringJoin[ToString[#], " represents a day of the week. ", ToString[#], "[] returns a corresponding numerical constant."])&, DayOfWeekNames[]] (* Names of standard months *) MonthNames[] = {January, February, March, April, May, June, July, August, September, October, November, December} Map[(Evaluate[#]::"usage" = StringJoin[ToString[#], " represents a month on the Julian and Gregorian calendars. ", ToString[#], "[] returns a corresponding numerical constant."])&, MonthNames[]] (* Conversions from fixed dates to week days *) DayOfWeekFromFixed::usage = "DayOfWeekFromFixed[fixedDate] returns the week day on which the given fixed date falls." (* Conversions between standard week days and standard week day names *) NameFromDayOfWeek::usage = "NameFromDayOfWeek[dayOfWeek] returns the name of the given week day." DayOfWeekNames::usage = "DayOfWeekNames[] returns a list of the names of the standard week days." (* Conversion between standard months and standard month names *) NameFromMonth::usage = "NameFromMonth[month] returns the name of the given standard month." MonthNames::usage = "MonthNames[] returns a list of the names of the standard months." (* Inspectors for components of dates and times *) Map[(Evaluate[#[[1]]]::"usage" = StringJoin[ToString[#[[1]]], "[date] returns the ", #[[2]], " component of the given calendar date. ", ToString[#[[1]]], "[] returns the set of calendars whose dates have a ", #[[2]], " component. "])&, { {CMonth, "month"}, {CDay, "day"}, {CYear, "year"}, {CWeek, "week"}, {CBaktun, "baktun"}, {CKatun, "katun"}, {CTun, "tun"}, {CUinal, "uinal"}, {CKin, "kin"}, {CNumber, "number"}, {CName, "name"}, {CMajor, "major"}, {CCycle, "cycle"}, {CLeap, "leap"}, {CLeapMonth, "leap month"}, {CLeapDay, "leap day"} }] (* Time of Day *) TimeOfDay::usage = "TimeOfDay represents a time of day. TimeOfDay[moment] returns the time of day from the given moment. TimeOfDay[] returns a list of components in a time of day." CHour::usage = "CHour[time] returns the hour component of the given time of day." CMinute::usage = "CMinute[time] returns the minute component of the given time of day." CSecond::usage = "CSecond[time] returns the second component of the given time of day." ToMoment::usage = "ToMoment[timeOfDay] returns the moment corresponding to the given time of day." (* General Calculations *) LeapYearQ::usage = "LeapYearQ[calendar, year] returns True if the given year is a leap year on the given calendar, and False otherwise. LeapYearQ[] returns the set of calendars which support LeapYearQ[calendar, year]" (* Conversion between fixed dates and Julian days *) JDStart::usage = "JDStart[] returns the fixed time of start of the Julian day number." MomentFromJD::usage = "MomentFromJD[jDay] returns the fixed moment corresponding to the given Julian day number." JDFromMoment::usage = "JDFromMoment[moment] returns the Julian day number corresponding to the given fixed moment." FixedFromJD::usage = "FixedFromJD[jDay] returns the fixed date (R.D.) corresponding to the given Julian day number." JDFromFixed::usage = "JDFromFixed[fixedDate] returns the Julian day number corresponding to the given fixed date." (* Gregorian Calendar *) IndependenceDay::usage = "IndependenceDay[gYear] returns the fixed date of American Independence Day in the given Gregorian year." KDayOnOrBefore::usage = "KDayOnOrBefore[fixedDate, k] returns the fixed date of the k-day on or before the given fixed date. A k-day of 0 means Sunday, 1 means Monday, etc." KDayOnOrAfter::usage = "KDayOnOrAfter[fixedDate, k] returns the fixed date of the k-day on or after the given fixed date. A k-day of 0 means Sunday, 1 means Monday, etc." KDayNearest::usage = "KDayNearest[fixedDate, k] returns the fixed date of the k-day nearest the given fixed date. A k-day of 0 means Sunday, 1 means Monday, etc." KDayAfter::usage = "KDayAfter[fixedDate, k] returns the fixed date of the k-day after the given fixed date. A k-day of 0 means Sunday, 1 means Monday, etc." KDayBefore::usage = "KDayBefore[fixedDate, k] returns the fixed date of the k-day before the given fixed date. A k-day of 0 means Sunday, 1 means Monday, etc." NthKDay::usage = "NthKDay[n, k, date] returns the fixed date of the n-th k-day after the given calendar date. If n > 0 the n-th k-day on or after the given date is returned. If n < 0, the n-th k-day on or before the given date is returned. A k-day of 0 means Sunday, 1 means Monday, etc." OFirst::usage = "OFirst[] returns an index for selecting a k-day." OLast::usage = "OLast[] returns an index for selecting a k-day." LaborDay::usage = "LaborDay[gYear] returns the fixed date of America Labor Day in the given Gregorian year-- the first Monday in September." MemorialDay::usage = "MemorialDay[gYear] returns the fixed date of American Memorial Day in the given Gregorian year-- the last Monday in May." ElectionDay::usage = "ElectionDay[gYear] returns the fixed date of American Election Day in the given Gregorian year-- the Tuesday after the first Monday in November." DaylightSavingsStart::usage = "DaylightSavingsStart[gYear] returns the fixed date of the start of American daylight savings time in the given Gregorian year-- the first Sunday in April." DaylightSavingsEnd::usage = "DaylightSavingsEnd[gYear] returns the fixed date of the end of American daylight savings time in the given Gregorian year-- the last Sunday in October." Christmas::usage = "Christmas[gYear] returns the fixed date of Christmas in the given Gregorian year." Advent::usage = "Advent[gYear] returns the fixed date of Advent in the given Gregorian year." Epiphany::usage = "Epiphany[gYear] returns the fixed date of Epiphany in the given Gregorian year." (* Julian Calendar *) NicaeanRuleEaster::usage = "NicaeanRuleEaster[jYear] returns the fixed date of Easter in the given positive Julian year, according to the rule of the Council of Nicaea." Easter::usage = "Easter[gYear] returns the fixed date of Easter in the given Gregorian year." JulianInGregorian::usage = "JulianInGregorian[jMonth, jDay, gYear] returns a list of the fixed dates of the given Julian month and day that occur in the given Gregorian year." EasternOrthodoxChristmas::usage = "EasternOrthodoxChristmas[gYear] returns a list of zero or one fixed dates of Eastern Orthodox Christmas in the given Gregorian year." Pentecost::usage = "Pentecost[gYear] returns the fixed date of Pentecost in the given Gregorian year." (* Coptic Calendar *) CopticInGregorian::usage = "CopticInGregorian[cMonth, cDay, gYear] returns a list of the fixed dates of the given Coptic month and day that occur in the given Gregorian year." CopticChristmas::usage = "CopticChristmas[gYear] returns a list of zero or one fixed dates of Coptic Christmas in the given Gregorian year." (* Islamic Calendar *) IslamicInGregorian::usage = "IslamicInGregorian[iMonth, iDay, gYear] returns a list of the fixed dates of the given Islamic month and day that occur in the given Gregorian year." MawlidAnNabi::usage = "MawlidAnNabi[gYear] returns a list of fixed dates of Mawlid-an-Nabi occurring in the given Gregorian year." (* Baha'i Calendar *) BahaiNewYear::usage = "BahaiNewYear[gYear] returns the fixed date of the Baha'i New Year in the given Gregorian year." FeastOfRidvan::usage = "FeastOfRidvan[gYear] returns the fixed date of the Baha'i Feast of Ridvan in the given Gregorian year." (* Persian Calendar *) NawRuz::usage = "NawRuz[gYear] returns the fixed date of the Persian New Year (Naw-Ruz) in the given Gregorian year." (* Hebrew Calendar *) YomKippur::usage = "YomKippur[gYear] returns the fixed date of Yom Kippur occurring in the given Gregorian year." Passover::usage = "Passover[gYear] returns the fixed date of Passover occurring in the given Gregorian year." Omer::usage = "Omer[fixedDate] returns a list of the form {weeks, days} containing the number of elapsed weeks and days in the omer at the given date. Returns Bogus if that date does not fall during the omer." Purim::usage = "Purim[gYear] returns the fixed date of Purim occurring in the given Gregorian year." TaAnithEsther::usage = "TaAnithEsther[gYear] returns the fixed date of Ta'anith Esther occurring in the given Gregorian year." TishaBAv::usage = "TishaBAv[gYear] returns the fixed date of Tisha B'Av occurring in the given Gregorian year." BirkathHaHama::usage = "BirkathHaHama[gYear] returns a list of the fixed dates of Birkath HaHama occurring in the given Gregorian year, if it occurs." ShEla::usage = "ShEla[gYear] returns the fixed date of Sh'ela occurring in the given Gregorian year." YomHaZikaron::usage = "YomHaZikarom[gYear] returns the fixed date of Yom HaZikaron occurring in the given Gregorian year." HebrewBirthday::usage = "HebrewBirthday[hBirthDate, hYear] returns the fixed date of the anniversary of the given Hebrew calendar date occurring in the given Hebrew year." Yahrzeit::usage = "Yahrzeit[hDeathDate, hYear] returns the fixed date of the anniversary of the given Hebrew death-date occurring in the given Hebrew year." (* Mayan Calendars *) MayanHaabDifference::usage = "MayanHaabDifference[hDate1, hDate2] returns the number of days from the first given Mayan haab calendar date hDate1 to the next occurrence of the second given Mayan haab calendar date hDate2." MayanHaabOnOrBefore::usage = "MayanHaabOnOrBefore[hDate, date] returns the fixed date of the latest date on or before the given fixed date that is the given Mayan haab calendar date hDate." MayanTzolkinDifference::usage = "MayanTzolkinDifference[tDate1, tDate2] returns the number of days from the first given Mayan Tzolkin calendar date tDate1 to the next occurrence of the second given Mayan Tzolkin calendar date tDate2." MayanTzolkinOnOrBefore::usage = "MayanTzolkinOnOrBefore[tDate, fixedDate] returns the fixed date of the latest date on or before the given fixed date that is Mayan tzolkin date tDate." MayanHaabTzolkinOnOrBefore::usage = "MayanHaabTzolkinOnOrBefore[hDate, tDate, fixedDate] returns the fixed date of the latest date on or before the given fixed date that is Mayan haab date hDate and tzolkin date tDate. Returns Bogus if such a haab-tzolkin combination is impossible." (* Old Hindu Calendars *) JovianYear::usage = "JovianYear[fixedDate] returns the year of the Jupiter cycle at the given fixed date." HinduDayCount::usage = "HinduDayCount[date] returns the number of elapsed days (Ahargana) to date since the Hindu epoch (K.Y.) from the given fixed date." (* Modern Hindu Calendars *) SunriseAtUjjain::usage = "SunriseAtUjjain[kyTime] returns the hindu-moment of astronomical sunrise at Ujjain (latitude 1389 minutes) at the give kyTime, in whole days since the Hindu epoch." LunarMansion::usage = "LunarMansion[date] returns the Hindu lunar mansion (nakshatra) at sunrise on the given fixed date." Samkranti::usage = "Samkranti[gYear, m] returns the fixed moment of the start of the m-th solar month of the Hindu year beginning in the given Gregorian year." MeshaSamkranti::usage = "MeshaSamkranti[gYear] returns the fixed moment of Mesha samkranti (Vernal equinox) in the given Gregorian year." HinduLunarNewYear::usage = "HinduLunarNewYear[gYear] returns the fixed date of the Hindu luni-solar new year in the given Gregorian year." Karana::usage = "Karana[n] returns the number (0-10) of the name of the n-th (1-60) Hindu karana." Yoga::usage = "Yoga[kyTime] returns the Hindu yoga at ky-time days since the Hindu epoch." SacredWednesdaysInGregorian::usage = "SacredWednesdaysInGregorian[gYear] returns a list of Wednesdays in the given Gregorian year that are day 8 of Hindu lunar months." SacredWednesdays::usage = "SacredWednesdays[start, end] returns a list of Wednesdays between the given fixed dates (inclusive) that are day 8 of Hindu lunar months." (* Time and Astronomy *) Sunrise::usage = "Sunrise[fixedDate, latitude, longitude] returns the local time (fraction of day) of sunrise at the given latitude (+ is N) and longitude (+ is E) (in nonpolar regions) for the given fixed date." Sunset::usage = "Sunset[fixedDate, latitude, longitude] returns the local time (fraction of day) of sunset at the given latitude (+ is N) and longitude (+ is E) (in nonpolar regions) for the given fixed date." LocalFromUniversal::usage = "LocalFromUniversal[uTime, zone] returns the local time (fraction of day) in the given time zone (in minutes of time after Greenwich) for the given universal time." UniversalFromLocal::usage = "UniversalFromLocal[lTime, zone] returns the universal time (fraction of day) for the given local time in the given time zone (in minutes of time after Greenwich)." LocalFromStandard::usage = "LocalFromStandard[sTime, offset] returns the local time (moment) from the given standard time (moment) at distance offset (in minutes) from the local time zone." StandardFromLocal::usage = "StandardFromLocal[lTime, offset] returns the standard time (moment) from the given local time (moment) at distance offset (in minutes) from the local time zone." LocalFromApparent::usage = "LocalFromApparent[moment] returns the local time from the given sundial time." ApparentFromLocal::usage = "ApparentFromLocal[moment] returns the sundial time at the given local time." SolarLongitude::usage = "SolarLongitude[jd] returns the longitude of the sun on the given astronomical (julian) day." DateNextSolarLongitude::usage = "DateNextSolarLongitude[jd, l] returns the Julian day number of the first date at or after julian day number jd (in Greenwich) when the solar longitude will be a multiple of l degrees; l must be a proper divisor of 360." LunarLongitude::usage = "LunarLongitude[uTime] returns the Longitude of the moon (in degrees) at uTime (Universal time)." NewMoonAtOrAfter::usage = "NewMoonAtOrAfter[jd] returns the astronomical (julian) day number of the first new moon at or after astronomical (julian) day number jd (in Greenwich). The fractional part is the time of day." NewMoonBefore::usage = "NewMoonBefore[jd] returns the astronomical (julian) day number of the last new moon before astronomical (julian) day number jd (in Greenwich). The fractional part is the time of day." New::usage = "New represents the new moon phase. New[] returns a corresponding excess of lunar longitude over solar longitude at the new moon." FirstQuarter::usage = "FirstQuarter represents the first quarter moon phase. FirstQuarter[] returns a corresponding excess of lunar longitude over solar longitude at the first quarter." Full::usage = "Full represents the new moon phase. Full[] returns a corresponding excess of lunar longitude over solar longitude at the full moon." LastQuarter::usage = "LastQuarter represents the last quarter moon phase. LastQuarter[] returns a corresponding excess of lunar longitude over solar longitude at the last quarter." LunarSolarAngle::usage = "LunarSolarAngle[jd] returns the lunar phase, as an angle in degrees, at astronomical (julian) day number jd. An angle of 0 means a new moon, 90 degrees means the first quarter, 180 means a full moon, and 270 degrees means the last quarter." LunarPhaseAtOrBefore::usage = "LunarPhaseAtOrBefore[phase, jd] returns the astronomical (julian) day number of last time moon was in phase phase (in degrees) at or before astronomical (julian) day number jd (in Greenwich). The fractional part is the time of day." NewMoonAtOrBefore::usage = "NewMoonAtOrBefore[jd] returns the astronomical (julian) day number of last new moon at or before astronomical (julian) day number jd (in Greenwich). The fractional part is the time of day." FullMoonAtOrBefore::usage = "FullMoonAtOrBefore[jd] returns the astronomical (julian) day number of last full moon at or before astronomical (julian) day number jd (in Greenwich). The fractional part is the time of day." FirstQuarterMoonAtOrBefore::usage = "FirstQuarterMoonAtOrBefore[jd] returns the astronomical (julian) day number of last first-quarter moon at or before astronomical (julian) day number jd (in Greenwich). The fractional part is the time of day." LastQuarterMoonAtOrBefore::usage = "LastQuarterMoonAtOrBefore[jd] returns the astronomical (julian) day number of last last-quarter moon at or before astronomical (julian) day number jd (in Greenwich). The fractional part is the time of day." SiderealFromJD::usage = "SiderealFromJD[jd] returns the siderial time from the given julian day number." (*----------------------------------------------------------------------------*) (* Conversion between fixed dates and calendar dates *) ToFixed::usage = "ToFixed[date] returns the fixed (R.D.) date corresponding to the given calendar date." (* Conversion between calendars *) ConvertDateTo::usage = "ConvertDateTo[date, calendar] converts the given calendar date to the specified calendar." (* Other manipulations on dates *) DateDifference::usage = "DateDifference[date1, date2] returns the number of days from calendar date 1 until calendar date 2, performing calendar conversion as necessary." DayNumber::usage = "DayNumber[date] returns the number of the day in the year of the given calendar date. DayNumber[] returns the set of calendars supported by DayNumber[date]." DaysRemaining::usage = "DaysRemaining[date] returns the number of days remaining in the year after the given calendar date. DaysRemaining[] returns the set of calendars supported by DaysRemaining[date]." (* Testing *) CalendricaTest::usage = "CalendricaTest[] runs a series of tests on the date conversion algorithms, comparing the results against test data transcribed from Appendix C of _Calendrical Calculations_ and elsewhere. As it runs, it prints a list of tests performed and either \"OK\" if the algorithms appear to be working correctly, or a lists containing any discrepancies found." (*----------------------------------------------------------------------------*) (*==================================================== Private Definitions ===*) (*----------------------------------------------------------------------------*) Begin["`Private`"] (** ;;;; Section: Basic Code **) (* ADDED *) Calendars[] = {Gregorian, ISO, Julian, Coptic, Ethiopic, Islamic, Persian, Bahai, Hebrew, MayanLongCount, MayanHaab, MayanTzolkin, OldHinduSolar, OldHinduLunar, French, ModifiedFrench, Chinese, HinduSolar, HinduLunar} LeapYearQ[] = {Gregorian, Julian, Coptic, Islamic, Persian, Hebrew, OldHinduLunar, ModifiedFrench} (** (defconstant false ;; TYPE boolean ;; Constant representing false. nil) **) (* False is a pre-defined Mathematica constant *) (** (defconstant bogus ;; TYPE string ;; Used to denote nonexistent dates. "bogus") **) Bogus (** (defun quotient (m n) ;; TYPE (real non-zero-real) -> integer ;; Whole part of m/n. (floor m n)) **) (* Quotient is a pre-defined Mathematica function defined exactly the same way as it is here *) (** (defun adjusted-mod (m n) ;; TYPE (integer positive-integer) -> positive-integer ;; Positive remainder of m/n with n instead of 0. (1+ (mod (1- m) n))) **) AdjustedMod[m_, n_] := Mod[m - 1, n] + 1 (** (defmacro sum (expression index initial condition) ;; TYPE ((integer->real) * integer (integer->boolean)) ;; TYPE -> real ;; Sum expression for index = initial and successive ;; integers, as long as condition holds. (let* ((temp (gensym))) `(do ((,temp 0 (+ ,temp ,expression)) (,index ,initial (1+ ,index))) ((not ,condition) ,temp)))) **) (* Since Sum is already a Mathematica function, we rename the sum macro MSum.*) MSum[expr_, initial_, condition_] := Module[{total, i}, For[total = 0; i = initial, condition[i], i++, total += expr[i]]; total ] (** (defmacro binary-search (l lo h hi x test end) ;; TYPE ( * real * real * (real->boolean) ;; TYPE ((real real)->boolean)) -> real ;; Bisection search for x in lo..hi such that end holds. ;; test determines when to go left. (let* ((left (gensym))) `(do* ((,x false (/ (+ ,h ,l) 2)) (,left false ,test) (,l ,lo (if ,left ,l ,x)) (,h ,hi (if ,left ,x ,h))) (,end (/ (+ ,h ,l) 2))))) **) BinarySearch[lo_, hi_, test_, end_] := Module[{l, h, x}, For[ l = lo; h = hi; x = (h + l) / 2, (* establish the low and high bounds, and the point between them *) !end[l, h], (* continue until the end condition is true *) Identity, (* no action in increment phase *) If[test[x], h = x, l = x]; (* body determines whether to go left or right, and resets the upper or lower bounds accordingly *) x = (h + l) / 2 (* then it resets the test point to lie between the bounds *) ]; x (* return the last test point visited *) ] (** (defmacro sigma (list body) ;; TYPE (list-of-pairs (list-of-reals->real)) ;; TYPE -> real ;; list is of the form ((i1 l1)..(in ln)). ;; Sum of body for indices i1..in ;; running simultaneously thru lists l1..ln. `(apply '+ (mapcar (function (lambda ,(mapcar 'car list) ,body)) ,@(mapcar 'cadr list)))) **) Sigma[list_, body_] := Apply[Plus, Apply[Function[Evaluate[Map[First, list]], body], Map[Part[#, 2]&, list] ]] (** (defun poly (x a) ;; TYPE (real list-of-reals) -> real ;; Sum powers of x with coefficients (from order 0 up) ;; in list a. (if (equal a nil) 0 (+ (first a) ( * x (poly x (cdr a)))))) **) Poly[x_, a_] := a[[1]] + Sum[a[[i]] x^(i - 1), {i, 2, Length[a]}] (** (defconstant sunday ;; TYPE day-of-week ;; Residue class for Sunday. 0) (defconstant monday ;; TYPE day-of-week ;; Residue class for Monday. (1+ sunday)) (defconstant tuesday ;; TYPE day-of-week ;; Residue class for Tuesday. (+ sunday 2)) (defconstant wednesday ;; TYPE day-of-week ;; Residue class for Wednesday. (+ sunday 3)) (defconstant thursday ;; TYPE day-of-week ;; Residue class for Thursday. (+ sunday 4)) (defconstant friday ;; TYPE day-of-week ;; Residue class for Friday. (+ sunday 5)) (defconstant saturday ;; TYPE day-of-week ;; Residue class for Saturday. (+ sunday 6)) **) Sunday[] = 0 Monday[] = Sunday[] + 1 Tuesday[] = Sunday[] + 2 Wednesday[] = Sunday[] + 3 Thursday[] = Sunday[] + 4 Friday[] = Sunday[] + 5 Saturday[] = Sunday[] + 6 (* ADDED *) NameFromNumber[number_Integer, nameList_List] := nameList[[ AdjustedMod[number, Length[nameList]] ]] (** (defun day-of-week-from-fixed (date) ;; TYPE fixed-date -> day-of-week ;; The residue class of the day of the week of date. (mod date 7)) **) DayOfWeekFromFixed[date_Integer] := Mod[date, 7] (* ADDED *) NameFromDayOfWeek[dayOfWeek_Integer] := NameFromNumber[dayOfWeek + 1, DayOfWeekNames[]] (** (defun standard-month (date) ;; TYPE standard-date -> standard-month ;; Month field of date = (month day year). (first date)) (defun standard-day (date) ;; TYPE standard-date -> standard-day ;; Day field of date = (month day year). (second date)) (defun standard-year (date) ;; TYPE standard-date -> standard-year ;; Year field of date = (month day year). (third date)) **) CMonth[ date_Gregorian | date_Julian | date_Islamic | date_Hebrew | date_French | date_ModifiedFrench | date_Coptic | date_Ethiopic | date_Persian | date_OldHinduSolar | date_HinduSolar] := date[[1]] CDay[ date_Gregorian | date_Julian | date_Islamic | date_Hebrew | date_French | date_ModifiedFrench | date_Coptic | date_Ethiopic | date_Persian | date_OldHinduSolar | date_HinduSolar] := date[[2]] CYear[ date_Gregorian | date_Julian | date_Islamic | date_Hebrew | date_French | date_ModifiedFrench | date_Coptic | date_Ethiopic | date_Persian | date_OldHinduSolar | date_HinduSolar] := date[[3]] (** (defun iso-week (date) ;; TYPE iso-date -> iso-week (first date)) (defun iso-day (date) ;; TYPE iso-date -> day-of-week (second date)) (defun iso-year (date) ;; TYPE iso-date -> iso-year (third date)) **) CWeek[date_ISO] := date[[1]] CDay[date_ISO] := date[[2]] CYear[date_ISO] := date[[3]] (** (defun mayan-baktun (date) ;; TYPE mayan-long-count-date -> mayan-baktun (first date)) (defun mayan-katun (date) ;; TYPE mayan-long-count-date -> mayan-katun (second date)) (defun mayan-tun (date) ;; TYPE mayan-long-count-date -> mayan-tun (third date)) (defun mayan-uinal (date) ;; TYPE mayan-long-count-date -> mayan-uinal (fourth date)) (defun mayan-kin (date) ;; TYPE mayan-long-count-date -> mayan-kin (fifth date)) **) CBaktun[date_MayanLongCount] := date[[1]] CKatun[date_MayanLongCount] := date[[2]] CTun[date_MayanLongCount] := date[[3]] CUinal[date_MayanLongCount] := date[[4]] CKin[date_MayanLongCount] := date[[5]] (** (defun mayan-haab-day (date) ;; TYPE mayan-haab-date -> mayan-haab-day (first date)) (defun mayan-haab-month (date) ;; TYPE mayan-haab-date -> mayan-haab-month (second date)) **) CDay[date_MayanHaab] := date[[1]] CMonth[date_MayanHaab] := date[[2]] (** (defun mayan-tzolkin-number (date) ;; TYPE mayan-tzolkin-date -> mayan-tzolkin-number (first date)) (defun mayan-tzolkin-name (date) ;; TYPE mayan-tzolkin-date -> mayan-tzolkin-name (second date)) **) CNumber[date_MayanTzolkin] := date[[1]] CName[date_MayanTzolkin] := date[[2]] (** (defun bahai-major (date) ;; TYPE bahai-date -> bahai-major (first date)) (defun bahai-cycle (date) ;; TYPE bahai-date -> bahai-cycle (second date)) (defun bahai-year (date) ;; TYPE bahai-date -> bahai-year (third date)) (defun bahai-month (date) ;; TYPE bahai-date -> bahai-month (fourth date)) (defun bahai-day (date) ;; TYPE bahai-date -> bahai-day (fifth date)) **) CMajor[date_Bahai] := date[[1]] CCycle[date_Bahai] := date[[2]] CYear[date_Bahai] := date[[3]] CMonth[date_Bahai] := date[[4]] CDay[date_Bahai] := date[[5]] (** (defun chinese-cycle (date) ;; TYPE chinese-date -> chinese-cycle (first date)) (defun chinese-year (date) ;; TYPE chinese-date -> chinese-year (second date)) (defun chinese-month (date) ;; TYPE chinese-date -> chinese-month (third date)) (defun chinese-leap (date) ;; TYPE chinese-date -> chinese-leap (fourth date)) (defun chinese-day (date) ;; TYPE chinese-date -> chinese-day (fifth date)) **) CCycle[date_Chinese] := date[[1]] CYear[date_Chinese] := date[[2]] CMonth[date_Chinese] := date[[3]] CLeap[date_Chinese] := date[[4]] CDay[date_Chinese] := date[[5]] (** (defun old-hindu-lunar-month (date) ;; TYPE old-hindu-lunar-date -> old-hindu-lunar-month (first date)) (defun old-hindu-lunar-leap (date) ;; TYPE old-hindu-lunar-date -> old-hindu-lunar-leap (second date)) (defun old-hindu-lunar-day (date) ;; TYPE old-hindu-lunar-date -> old-hindu-lunar-day (third date)) (defun old-hindu-lunar-year (date) ;; TYPE old-hindu-lunar-date -> old-hindu-lunar-year (fourth date)) **) CMonth[date_OldHinduLunar] := date[[1]] CLeap[date_OldHinduLunar] := date[[2]] CDay[date_OldHinduLunar] := date[[3]] CYear[date_OldHinduLunar] := date[[4]] (** (defun hindu-lunar-month (date) ;; TYPE hindu-lunar-date -> hindu-lunar-month (first date)) (defun hindu-lunar-leap-month (date) ;; TYPE hindu-lunar-date -> hindu-lunar-leap-month (second date)) (defun hindu-lunar-day (date) ;; TYPE hindu-lunar-date -> hindu-lunar-day (third date)) (defun hindu-lunar-leap-day (date) ;; TYPE hindu-lunar-date -> hindu-lunar-leap-day (fourth date)) (defun hindu-lunar-year (date) ;; TYPE hindu-lunar-date -> hindu-lunar-year (fifth date)) **) CMonth[date_HinduLunar] := date[[1]] CLeapMonth[date_HinduLunar] := date[[2]] CDay[date_HinduLunar] := date[[3]] CLeapDay[date_HinduLunar] := date[[4]] CYear[date_HinduLunar] := date[[5]] (* ADDED *) CHour[time_TimeOfDay] := time[[1]] CMinute[time_TimeOfDay] := time[[2]] CSecond[time_TimeOfDay] := time[[3]] (* ADDED *) CMonth[] = {Gregorian, Julian, Islamic, Hebrew, French, ModifiedFrench, Coptic, Ethiopic, Persian, OldHinduSolar, HinduSolar, Bahai, Chinese, OldHinduLunar, HinduLunar} CDay[] = {Gregorian, Julian, Islamic, Hebrew, French, ModifiedFrench, Coptic, Ethiopic, Persian, OldHinduSolar, HinduSolar, ISO, MayanHaab, Bahai, Chinese, OldHinduLunar, HinduLunar} CYear[] = {Gregorian, Julian, Islamic, Hebrew, French, ModifiedFrench, Coptic, Ethiopic, Persian, OldHinduSolar, HinduSolar, ISO, MayanHaab, Bahai, Chinese, OldHinduLunar, HinduLunar} CWeek[] = {ISO} CBaktun[] = {MayanLongCount} CKatun[] = {MayanLongCount} CTun[] = {MayanLongCount} CUinal[] = {MayanLongCount} CKin[] = {MayanLongCount} CNumber[] = {MayanTzolkin} CName[] = {MayanTzolkin} CMajor[] = {Bahai} CCycle[] = {Bahai, Chinese} CLeap[] = {Chinese, OldHinduLunar} CLeapMonth[] = {HinduLunar} CLeapDay[] = {HinduLunar} Gregorian[] = {CMonth, CDay, CYear} Julian[] = {CMonth, CDay, CYear} Islamic[] = {CMonth, CDay, CYear} Hebrew[] = {CMonth, CDay, CYear} French[] = {CMonth, CDay, CYear} ModifiedFrench[] = {CMonth, CDay, CYear} Coptic[] = {CMonth, CDay, CYear} Ethiopic[] = {CMonth, CDay, CYear} Persian[] = {CMonth, CDay, CYear} OldHinduSolar[] = {CMonth, CDay, CYear} HinduSolar[] = {CMonth, CDay, CYear} ISO[] = {CWeek, CDay, CYear} MayanLongCount[] = {CBaktun, CKatun, CTun, CUinal, CKin} MayanHaab[] = {CDay, CMonth} MayanTzolkin[] = {CNumber, CName} Chinese[] = {CCycle, CYear, CMonth, CLeap, CDay} Bahai[] = {CMajor, CCycle, CYear, CMonth, CDay} OldHinduLunar[] = {CMonth, CLeap, CDay, CYear} HinduLunar[] = {CMonth, CLeapMonth, CDay, CLeapDay, CYear} TimeOfDay[] = {CHour, CMinute, CSecond} (** (defun gregorian-date (month day year) ;; TYPE (gregorian-month gregorian-day gregorian-year) ;; TYPE -> gregorian-date (list month day year)) (defun julian-date (month day year) ;; TYPE (julian-month julian-day julian-year) ;; TYPE -> julian-date (list month day year)) (defun islamic-date (month day year) ;; TYPE (islamic-month islamic-day islamic-year) ;; TYPE -> islamic-date (list month day year)) (defun hebrew-date (month day year) ;; TYPE (hebrew-month hebrew-day hebrew-year) -> hebrew-date (list month day year)) (defun french-date (month day year) ;; TYPE (french-month french-day french-year) -> french-date (list month day year)) (defun coptic-date (month day year) ;; TYPE (coptic-month coptic-day coptic-year) -> coptic-date (list month day year)) (defun ethiopic-date (month day year) ;; TYPE (ethiopic-month ethiopic-day ethiopic-year) ;; TYPE -> ethiopic-date (list month day year)) (defun persian-date (month day year) ;; TYPE (persian-month persian-day persian-year) ;; TYPE -> persian-date (list month day year)) (defun hindu-solar-date (month day year) ;; TYPE (hindu-solar-month hindu-solar-day hindu-solar-year) ;; TYPE -> hindu-solar-date (list month day year)) (defun time-of-day (hour minute second) ;; TYPE (hour minute second) -> moment (list hour minute second)) (defun iso-date (week day year) ;; TYPE (iso-week iso-day iso-year) -> iso-date (list week day year)) (defun mayan-long-count-date (baktun katun tun uinal kin) ;; TYPE (mayan-baktun mayan-katun mayan-tun mayan-uinal ;; TYPE mayan-kin) -> mayan-long-count-date (list baktun katun tun uinal kin)) (defun mayan-haab-date (day month) ;; TYPE (mayan-haab-day mayan-haab-month) -> mayan-haab-date (list day month)) (defun mayan-tzolkin-date (number name) ;; TYPE (mayan-tzolkin-number mayan-tzolkin-name) ;; TYPE -> mayan-tzolkin-date (list number name)) (defun chinese-date (cycle year month leap day) ;; TYPE (chinese-cycle chinese-year chinese-month ;; TYPE chinese-leap chinese-day) -> chinese-date (list cycle year month leap day)) (defun bahai-date (major cycle year month day) ;; TYPE (bahai-major bahai-cycle bahai-year ;; TYPE bahai-month bahai-day) -> bahai-date (list major cycle year month day)) (defun old-hindu-lunar-date (month leap day year) ;; TYPE (old-hindu-lunar-month old-hindu-lunar-leap ;; TYPE old-hindu-lunar-day old-hindu-lunar-year) ;; TYPE -> old-hindu-lunar-date (list month leap day year)) (defun hindu-lunar-date (month leap-month day leap-day year) ;; TYPE (hindu-lunar-month hindu-lunar-leap-month ;; TYPE hindu-lunar-day hindu-lunar-leap-day ;; TYPE hindu-lunar-year) -> hindu-lunar-date (list month leap-month day leap-day year)) **) (* Not needed in Mathematica; simply write [, , ... ] or TimeOfDay[, , ] *) (** (defconstant jd-start ;; TYPE moment ;; Fixed time of start of the julian day number. -1721424.5) **) JDStart[] = -1721424.5 (** (defun moment-from-jd (jd) ;; TYPE julian-day-number -> moment ;; Fixed time of astronomical (julian) day number jd. (+ jd jd-start)) **) MomentFromJD[jd_] := jd + JDStart[] (** (defun fixed-from-jd (jd) ;; TYPE julian-day-number -> fixed-date ;; Fixed date of astronomical (julian) day number jd. (floor (moment-from-jd jd))) **) FixedFromJD[jd_] := Floor[MomentFromJD[jd]] (** (defun jd-from-moment (moment) ;; TYPE moment -> julian-day-number ;; Astronomical (julian) day number of fixed moment moment. (- moment jd-start)) **) JDFromMoment[moment_] := moment - JDStart[] (* ADDED *) JDFromFixed[date_] := JDFromMoment[date] (** ;;;; Section: Gregorian Calendar **) (** (defconstant gregorian-epoch ;; TYPE fixed-date ;; Fixed date of start of the (proleptic) Gregorian ;; calendar. 1) **) GregorianEpoch[] = 1 (* (defconstant january ;; TYPE standard-month ;; January on Julian/Gregorian calendar. 1) (defconstant february ;; TYPE standard-month ;; February on Julian/Gregorian calendar. (1+ january)) (defconstant march ;; TYPE standard-month ;; March on Julian/Gregorian calendar. (+ january 2)) (defconstant april ;; TYPE standard-month ;; April on Julian/Gregorian calendar. (+ january 3)) (defconstant may ;; TYPE standard-month ;; May on Julian/Gregorian calendar. (+ january 4)) (defconstant june ;; TYPE standard-month ;; June on Julian/Gregorian calendar. (+ january 5)) (defconstant july ;; TYPE standard-month ;; July on Julian/Gregorian calendar. (+ january 6)) (defconstant august ;; TYPE standard-month ;; August on Julian/Gregorian calendar. (+ january 7)) (defconstant september ;; TYPE standard-month ;; September on Julian/Gregorian calendar. (+ january 8)) (defconstant october ;; TYPE standard-month ;; October on Julian/Gregorian calendar. (+ january 9)) (defconstant november ;; TYPE standard-month ;; November on Julian/Gregorian calendar. (+ january 10)) (defconstant december ;; TYPE standard-month ;; December on Julian/Gregorian calendar. (+ january 11)) **) January[] = 1 February[] = January[] + 1 March[] = January[] + 2 April[] = January[] + 3 May[] = January[] + 4 June[] = January[] + 5 July[] = January[] + 6 August[] = January[] + 7 September[] = January[] + 8 October[] = January[] + 9 November[] = January[] + 10 December[] = January[] + 11 (* ADDED *) NameFromMonth[month_] := NameFromNumber[month, MonthNames[]] (** (defun gregorian-leap-year? (g-year) ;; TYPE gregorian-year -> boolean ;; True if year is a leap year on the Gregorian calendar. (and (= (mod g-year 4) 0) (not (member (mod g-year 400) (list 100 200 300))))) **) LeapYearQ[Gregorian, year_] := Mod[year, 4] == 0 && !MemberQ[{100, 200, 300}, Mod[year, 400]] (** (defun fixed-from-gregorian (g-date) ;; TYPE gregorian-date -> fixed-date ;; Fixed date equivalent to the Gregorian date. (let* ((month (standard-month g-date)) (day (standard-day g-date)) (year (standard-year g-date))) (+ (1- gregorian-epoch); Days before start of calendar ( * 365 (1- year)); Ordinary days since epoch (quotient (1- year) 4); Julian leap days since epoch... (- ; ...minus century years since epoch... (quotient (1- year) 100)) (quotient ; ...plus years since epoch divisible... (1- year) 400) ; ...by 400. (quotient ; Days in prior months this year... (- ( * 367 month) 362); ...assuming 30-day Feb 12) (if (<= month 2) ; Correct for 28- or 29-day Feb 0 (if (gregorian-leap-year? year) -1 -2)) day))) ; Days so far this month. **) ToFixed[date_Gregorian] := Module[{month = CMonth[date], year = CYear[date]}, (GregorianEpoch[] - 1) + 365 (year - 1) + Quotient[year - 1, 4] - Quotient[year - 1, 100] + Quotient[year - 1, 400] + Quotient[367 month - 362, 12] + If[month <= 2, 0, If[LeapYearQ[Gregorian, year], -1, -2]] + CDay[date] ] (** (defun gregorian-year-from-fixed (date) ;; TYPE fixed-date -> gregorian-year ;; Gregorian year corresponding to the fixed date. (let* ((d0 ; Prior days. (- date gregorian-epoch)) (n400 ; Completed 400-year cycles. (quotient d0 146097)) (d1 ; Prior days not in n400. (mod d0 146097)) (n100 ; 100-year cycles not in n400. (quotient d1 36524)) (d2 ; Prior days not in n400 or n100. (mod d1 36524)) (n4 ; 4-year cycles not in n400 or n100. (quotient d2 1461)) (d3 ; Prior days not in n400, n100, or n4. (mod d2 1461)) (n1 ; Years not in n400, n100, or n4. (quotient d3 365)) (d4 ; Prior days not in n400, n100, n4, or n1. (1+ (mod d3 365))) (year (+ ( * 400 n400) ( * 100 n100) ( * 4 n4) n1))) (if (or (= n100 4) (= n1 4)) year ; Date is December 31 in year. (1+ year)))); Date is ordinal day (1+ d4) in (1+ year). **) GregorianYearFromFixed[date_] := Module[{d0, n400, d1, n100, d2, n4, d3, n1, d4, year}, d0 = date - GregorianEpoch[]; n400 = Quotient[d0, 146097]; d1 = Mod[d0, 146097]; n100 = Quotient[d1, 36524]; d2 = Mod[d1, 36524]; n4 = Quotient[d2, 1461]; d3 = Mod[d2, 1461]; n1 = Quotient[d3, 365]; d4 = Mod[d3, 365] + 1; year = 400 n400 + 100 n100 + 4 n4 + n1; If[n100 == 4 || n1 == 4, year, year + 1] ] (** (defun gregorian-from-fixed (date) ;; TYPE fixed-date -> gregorian-date ;; Gregorian (month day year) corresponding to fixed date. (let* ((year (gregorian-year-from-fixed date)) (prior-days; This year (- date (fixed-from-gregorian (gregorian-date january 1 year)))) (correction; To simulate a 30-day Feb (if (< date (fixed-from-gregorian (gregorian-date march 1 year))) 0 (if (gregorian-leap-year? year) 1 2))) (month ; Assuming a 30-day Feb (quotient (+ ( * 12 (+ prior-days correction)) 373) 367)) (day ; Calculate the day by subtraction. (1+ (- date (fixed-from-gregorian (gregorian-date month 1 year)))))) (gregorian-date month day year))) **) Gregorian[date_Integer] := Module[{year, priorDays, correction, month, day}, year = GregorianYearFromFixed[date]; priorDays = date - ToFixed[ Gregorian[January[], 1, year] ]; correction = If[ date < ToFixed[ Gregorian[March[], 1, year] ], 0, If[ LeapYearQ[Gregorian, year], 1, 2] ]; month = Quotient[12 (priorDays + correction) + 373, 367]; day = date - ToFixed[ Gregorian[month, 1, year] ] + 1; Gregorian[month, day, year] ] (** (defun gregorian-date-difference (g-date1 g-date2) ;; TYPE (gregorian-date gregorian-date) -> integer ;; Number of days from Gregorian date g-date1 until g-date2. (- (fixed-from-gregorian g-date2) (fixed-from-gregorian g-date1))) **) DateDifference[date1_, date2_] := ToFixed[date2] - ToFixed[date1] (** (defun day-number (g-date) ;; TYPE gregorian-date -> non-negative-integer ;; Day number in year of Gregorian date g-date. (gregorian-date-difference (gregorian-date december 31 (1- (standard-year g-date))) g-date)) **) DayNumber[] = {Gregorian} DayNumber[date_Gregorian] := DateDifference[Gregorian[December[], 31, CYear[date] - 1], date] (** (defun days-remaining (g-date) ;; TYPE gregorian-date -> non-negative-integer ;; Days remaining in year after Gregorian date g-date. (gregorian-date-difference g-date (gregorian-date december 31 (standard-year g-date)))) **) DaysRemaining[] = {Gregorian} DaysRemaining[date_Gregorian] := DateDifference[date, Gregorian[December[], 31, CYear[date]]] (** (defun independence-day (year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of American Independence Day in ;; Gregorian year. (fixed-from-gregorian (gregorian-date july 4 year))) **) IndependenceDay[year_] := ToFixed[Gregorian[July[], 4, year]]; (** (defun kday-on-or-before (date k) ;; TYPE (fixed-date weekday) -> fixed-date ;; Fixed date of the k-day on or before fixed date. ;; k=0 means Sunday, k=1 means Monday, and so on. (- date (day-of-week-from-fixed (- date k)))) **) KDayOnOrBefore[date_, k_] := date - DayOfWeekFromFixed[date - k] (** (defun kday-on-or-after (date k) ;; TYPE (fixed-date weekday) -> fixed-date ;; Fixed date of the k-day on or after fixed date. ;; k=0 means Sunday, k=1 means Monday, and so on. (kday-on-or-before (+ date 6) k)) **) KDayOnOrAfter[date_, k_] := KDayOnOrBefore[date + 6, k] (** (defun kday-nearest (date k) ;; TYPE (fixed-date weekday) -> fixed-date ;; Fixed date of the k-day nearest fixed date. k=0 ;; means Sunday, k=1 means Monday, and so on. (kday-on-or-before (+ date 3) k)) **) KDayNearest[date_, k_] := KDayOnOrBefore[date + 3, k] (** (defun kday-after (date k) ;; TYPE (fixed-date weekday) -> fixed-date ;; Fixed date of the k-day after fixed date. k=0 ;; means Sunday, k=1 means Monday, and so on. (kday-on-or-before (+ date 7) k)) **) KDayAfter[date_, k_] := KDayOnOrBefore[date + 7, k] (** (defun kday-before (date k) ;; TYPE (fixed-date weekday) -> fixed-date ;; Fixed date of the k-day before fixed date. k=0 ;; means Sunday, k=1 means Monday, and so on. (kday-on-or-before (1- date) k)) **) KDayBefore[date_, k_] := KDayOnOrBefore[date - 1, k] (** (defun nth-kday (n k date) ;; TYPE (integer weekday gregorian-date) -> fixed-date ;; Fixed date of n-th k-day after Gregorian date. If ;; n>0, return the n-th k-day on or after date. ;; If n<0, return the n-th k-day on or before date. ;; A k-day of 0 means Sunday, 1 means Monday, and so on. (if (> n 0) (+ ( * 7 n) (kday-before (fixed-from-gregorian date) k)) (+ ( * 7 n) (kday-after (fixed-from-gregorian date) k)))) **) NthKDay[n_, k_, date_] := If[n > 0, KDayBefore[ToFixed[date], k] + 7 n, KDayAfter[ToFixed[date], k] + 7 n] (** (defconstant first ;; TYPE integer ;; Index for selecting a k-day. 1) (defconstant last ;; TYPE integer ;; Index for selecting a k-day. -1) **) OFirst[] = 1 OLast[] = -1 (** (defun labor-day (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of American Labor Day in Gregorian ;; year--the first Monday in September. (nth-kday first monday (gregorian-date september 1 g-year))) **) LaborDay[year_] := NthKDay[OFirst[], Monday[], Gregorian[September[], 1, year]] (** (defun memorial-day (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of American Memorial Day in Gregorian ;; year--the last Monday in May. (nth-kday last monday (gregorian-date may 31 g-year))) **) MemorialDay[year_] := NthKDay[OLast[], Monday[], Gregorian[May[], 31, year]] (** (defun election-day (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of American Election Day in Gregorian ;; year--the Tuesday after the first Monday in November. (nth-kday first tuesday (gregorian-date november 2 g-year))) **) ElectionDay[year_] := NthKDay[OFirst[], Tuesday[], Gregorian[November[], 2, year]] (** (defun daylight-savings-start (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of the start of American daylight savings ;; time in Gregorian year--the first Sunday in April. (nth-kday first sunday (gregorian-date april 1 g-year))) **) DaylightSavingsStart[year_] := NthKDay[OFirst[], Sunday[], Gregorian[April[], 1, year]] (** (defun daylight-savings-end (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of the end of American daylight savings time ;; in Gregorian year--the last Sunday in October. (nth-kday last sunday (gregorian-date october 31 g-year))) **) DaylightSavingsEnd[year_] := NthKDay[OLast[], Sunday[], Gregorian[October[], 31, year]] (** (defun christmas (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Christmas in Gregorian year. (fixed-from-gregorian (gregorian-date december 25 g-year))) **) Christmas[year_] := ToFixed[Gregorian[December[], 25, year]] (** (defun advent (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Advent in Gregorian year. (kday-nearest (fixed-from-gregorian (gregorian-date november 30 g-year)) sunday)) **) Advent[year_] := KDayNearest[ToFixed[Gregorian[November[], 30, year]], Sunday[]] (** (defun epiphany (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Epiphany in Gregorian year. (+ 12 (christmas (1- g-year)))) **) Epiphany[year_] := Christmas[year - 1] + 12 (** ;;;; Section: ISO Calendar **) (** (defun fixed-from-iso (i-date) ;; TYPE iso-date -> fixed-date ;; Fixed date equivalent to ISO (week day year). (let* ((week (iso-week i-date)) (day (iso-day i-date)) (year (iso-year i-date))) ;; Add fixed date of Sunday preceding date plus day ;; in week. (+ (nth-kday week sunday (gregorian-date december 28 (1- year))) day))) **) ToFixed[date_ISO] := NthKDay[CWeek[date], Sunday[], Gregorian[December[], 28, CYear[date] - 1]] + CDay[date] (** (defun iso-from-fixed (date) ;; TYPE fixed-date -> iso-date ;; ISO (week day year) corresponding to the fixed date. (let* ((approx ; Year may be one too small. (gregorian-year-from-fixed (- date 3))) (year (if (>= date (fixed-from-iso (iso-date 1 1 (1+ approx)))) (1+ approx) approx)) (week (1+ (quotient (- date (fixed-from-iso (iso-date 1 1 year))) 7))) (day (adjusted-mod date 7))) (iso-date week day year))) **) ISO[date_Integer] := Module[{approx, year, week, day}, approx = GregorianYearFromFixed[date - 3]; year = If[ date >= ToFixed[ISO[1, 1, approx + 1]], approx + 1, approx]; week = Quotient[date - ToFixed[ ISO[1, 1, year] ], 7] + 1; day = AdjustedMod[date, 7]; ISO[week, day, year] ] (** ;;;; Section: Julian Calendar **) (** (defconstant julian-epoch ;; TYPE fixed-date ;; Fixed date of start of the Julian calendar. (fixed-from-gregorian (gregorian-date december 30 0))) **) JulianEpoch[] = ToFixed[Gregorian[December[], 30, 0]] (** (defun bce (n) ;; TYPE standard-year -> julian-year ;; Negative value to indicate a BCE Julian year. (- n)) **) BCE[n_] := - n (** (defun ce (n) ;; TYPE standard-year -> julian-year ;; Positive value to indicate a CE Julian year. n) **) CE[n_] := n (** (defun julian-leap-year? (j-year) ;; TYPE julian-year -> boolean ;; True if year is a leap year on the Julian calendar. (= (mod j-year 4) (if (> j-year 0) 0 3))) **) LeapYearQ[Julian, year_] := Mod[year, 4] == If[year > 0, 0, 3] (** (defun fixed-from-julian (j-date) ;; TYPE julian-date -> fixed-date ;; Fixed date equivalent to the Julian date. (let* ((month (standard-month j-date)) (day (standard-day j-date)) (year (standard-year j-date)) (y (if (< year 0) (1+ year) ; No year zero year))) (+ (1- julian-epoch) ; Days before start of calendar ( * 365 (1- y)) ; Ordinary days since epoch. (quotient (1- y) 4); Leap days since epoch... (quotient ; Days in prior months this year... (- ( * 367 month) 362); ...assuming 30-day Feb 12) (if (<= month 2) ; Correct for 28- or 29-day Feb 0 (if (julian-leap-year? year) -1 -2)) day))) ; Days so far this month. **) ToFixed[date_Julian] := Module[{month, day, year, y}, month = CMonth[date]; day = CDay[date]; year = CYear[date]; y = If[year < 0, year + 1, year]; JulianEpoch[] - 1 + 365 (y - 1) + Quotient[y - 1, 4] + Quotient[367 month - 362, 12] + If[month <= 2, 0, If[LeapYearQ[Julian, year], -1, -2]] + day ] (** (defun julian-from-fixed (date) ;; TYPE fixed-date -> julian-date ;; Julian (month day year) corresponding to fixed date. (let* ((approx ; Nominal year. (quotient (+ ( * 4 (- date julian-epoch)) 1464) 1461)) (year (if (<= approx 0) (1- approx) ; No year 0. approx)) (prior-days; This year (- date (fixed-from-julian (julian-date january 1 year)))) (correction; To simulate a 30-day Feb (if (< date (fixed-from-julian (julian-date march 1 year))) 0 (if (julian-leap-year? year) 1 2))) (month ; Assuming a 30-day Feb (quotient (+ ( * 12 (+ prior-days correction)) 373) 367)) (day ; Calculate the day by subtraction. (1+ (- date (fixed-from-julian (julian-date month 1 year)))))) (julian-date month day year))) **) Julian[date_Integer] := Module[{approx, year, priorDays, correction, month}, approx = Quotient[4 (date - JulianEpoch[]) + 1464, 1461]; year = If[approx <= 0, approx - 1, approx]; priorDays = date - ToFixed[Julian[January[], 1, year]]; correction = If[date < ToFixed[Julian[March[], 1, year]], 0, If[LeapYearQ[Julian, year], 1, 2]]; month = Quotient[12 (priorDays + correction) + 373, 367]; day = date - ToFixed[Julian[month, 1, year]] + 1; Julian[month, day, year] ] (** (defun nicaean-rule-easter (j-year) ;; TYPE julian-year -> fixed-date ;; Fixed date of Easter in positive Julian year, according ;; to the rule of the Council of Nicaea. (let* ((shifted-epact ; Age of moon for April 5. (mod (+ 14 ( * 11 (mod j-year 19))) 30)) (paschal-moon ; Day after full moon on ; or after March 21. (- (fixed-from-julian (julian-date april 19 j-year)) shifted-epact))) ;; Return the Sunday following the Paschal moon (kday-after paschal-moon sunday))) **) NicaeanRuleEaster[jYear_] := Module[{shiftedEpact, paschalMoon}, shiftedEpact = Mod[14 + 11 Mod[jYear, 19], 30]; paschalMoon = ToFixed[Julian[April[], 19, jYear]] - shiftedEpact; KDayAfter[paschalMoon, Sunday[]] ] (** (defun easter (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Easter in Gregorian year. (let* ((century (1+ (quotient g-year 100))) (shifted-epact ; Age of moon for April 5... (mod (+ 14 ( * 11 (mod g-year 19)); ...by Nicaean rule (- ;...corrected for the Gregorian century rule (quotient ( * 3 century) 4)) (quotient; ...corrected for Metonic ; cycle inaccuracy. (+ 5 ( * 8 century)) 25)) 30)) (adjusted-epact ; Adjust for 29.5 day month. (if (or (= shifted-epact 0) (and (= shifted-epact 1) (< 10 (mod g-year 19)))) (1+ shifted-epact) shifted-epact)) (paschal-moon; Day after full moon on ; or after March 21. (- (fixed-from-gregorian (gregorian-date april 19 g-year)) adjusted-epact))) ;; Return the Sunday following the Paschal moon. (kday-after paschal-moon sunday))) **) Easter[gYear_] := Module[{century, shiftedEpact, adjustedEpact, paschalMoon}, century = 1 + Quotient[gYear, 100]; shiftedEpact = Mod[14 + 11 Mod[gYear, 19] - Quotient[3 century, 4] + Quotient[5 + 8 century, 25], 30]; adjustedEpact = If[shiftedEpact == 0 || (shiftedEpact == 1 && 10 < Mod[gYear, 19]), shiftedEpact + 1, shiftedEpact]; paschalMoon = ToFixed[Gregorian[April[], 19, gYear]] - adjustedEpact; KDayAfter[paschalMoon, Sunday[]] ] (** (defun pentecost (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Pentecost in Gregorian year. (+ (easter g-year) 49)) **) Pentecost[gYear_] := Easter[gYear] + 49 (** (defun julian-in-gregorian (j-month j-day g-year) ;; TYPE (julian-month julian-day gregorian-year) ;; TYPE -> list-of-fixed-dates ;; List of the fixed dates of Julian month, day ;; that occur in Gregorian year. (let* ((jan1 (fixed-from-gregorian (gregorian-date january 1 g-year))) (dec31 (fixed-from-gregorian (gregorian-date december 31 g-year))) (y (standard-year (julian-from-fixed jan1))) ;; The possible occurrences in one year are (date1 (fixed-from-julian (julian-date j-month j-day y))) (date2 (fixed-from-julian (julian-date j-month j-day (1+ y))))) (append (if ; date1 occurs in current year (<= jan1 date1 dec31) ;; Then that date; otherwise, none (list date1) nil) (if ; date2 occurs in current year (<= jan1 date2 dec31) ;; Then that date; otherwise, none (list date2) nil)))) **) JulianInGregorian[jMonth_, jDay_, gYear_] := Module[{jan1, dec31, y, date1, date2, result}, jan1 = ToFixed[Gregorian[January[], 1, gYear]]; dec31 = ToFixed[Gregorian[December[], 31, gYear]]; y = CYear[Julian[jan1]]; date1 = ToFixed[Julian[jMonth, jDay, y]]; date2 = ToFixed[Julian[jMonth, jDay, y + 1]]; result = {}; If[LessEqual[jan1, date1, dec31], result = Append[result, date1]]; If[LessEqual[jan1, date2, dec31], result = Append[result, date2]]; result ] (** (defun eastern-orthodox-christmas (g-year) ;; TYPE gregorian-year -> list-of-fixed-dates ;; List of zero or one fixed dates of Eastern Orthodox ;; Christmas in Gregorian year. (julian-in-gregorian december 25 g-year)) **) EasternOrthodoxChristmas[gYear_] := JulianInGregorian[December[], 25, gYear] (** ;;;; Section: Coptic and Ethiopic Calendars **) (** (defconstant coptic-epoch ;; TYPE fixed-date ;; Fixed date of start of the Coptic calendar. (fixed-from-julian (julian-date august 29 (ce 284)))) **) CopticEpoch[] = ToFixed[Julian[August[], 29, CE[284]]] (** (defun coptic-leap-year? (c-year) ;; TYPE coptic-year -> boolean ;; True if year is a leap year on the Coptic calendar. (= (mod c-year 4) 3)) **) LeapYearQ[Coptic, year_] := Mod[year, 4] == 3 (** (defun fixed-from-coptic (c-date) ;; TYPE coptic-date -> fixed-date ;; Fixed date of Coptic date. (let* ((month (standard-month c-date)) (day (standard-day c-date)) (year (standard-year c-date))) (+ coptic-epoch -1 ; Days before start of calendar ( * 365 (1- year)); Ordinary days in prior years (quotient year 4); Leap days in prior years ( * 30 (1- month)); Days in prior months this year day))) ; Days so far this month **) ToFixed[date_Coptic] := Module[{year}, year = CYear[date]; CopticEpoch[] - 1 + 365 (year - 1) + Quotient[year, 4] + 30 (CMonth[date] - 1) + CDay[date] ] (** (defun coptic-from-fixed (date) ;; TYPE fixed-date -> coptic-date ;; Coptic equivalent of fixed date. (let* ((year ; Calculate the year by cycle-of-years formula (quotient (+ ( * 4 (- date coptic-epoch)) 1463) 1461)) (month; Calculate the month by division. (1+ (quotient (- date (fixed-from-coptic (coptic-date 1 1 year))) 30))) (day ; Calculate the day by subtraction. (- date -1 (fixed-from-coptic (coptic-date month 1 year))))) (coptic-date month day year))) **) Coptic[date_Integer] := Module[{year, month, day}, year = Quotient[4 (date - CopticEpoch[]) + 1463, 1461]; month = Quotient[date - ToFixed[Coptic[1, 1, year]], 30] + 1; day = date + 1 - ToFixed[Coptic[month, 1, year]]; Coptic[month, day, year] ] (** (defconstant ethiopic-epoch ;; TYPE fixed-date ;; Fixed date of start of the Ethiopic calendar. (fixed-from-julian (julian-date august 29 (ce 7)))) **) EthiopicEpoch[] = ToFixed[Julian[August[], 29, CE[7]]] (** (defun fixed-from-ethiopic (e-date) ;; TYPE ethiopic-date -> fixed-date ;; Fixed date of Ethiopic date. (let* ((month (standard-month e-date)) (day (standard-day e-date)) (year (standard-year e-date))) (+ ethiopic-epoch (- (fixed-from-coptic (coptic-date month day year)) coptic-epoch)))) **) ToFixed[date_Ethiopic] := ToFixed[Coptic[CMonth[date], CDay[date], CYear[date]]] - CopticEpoch[] + EthiopicEpoch[] (** (defun ethiopic-from-fixed (date) ;; TYPE fixed-date -> ethiopic-date ;; Ethiopic equivalent of fixed date. (coptic-from-fixed (+ date (- coptic-epoch ethiopic-epoch)))) **) Ethiopic[date_Integer] := Apply[Ethiopic, Coptic[date + CopticEpoch[] - EthiopicEpoch[]]] (** (defun coptic-in-gregorian (c-month c-day g-year) ;; TYPE (coptic-month coptic-day gregorian-year) ;; TYPE -> list-of-fixed-dates ;; List of the fixed dates of Coptic month, day ;; that occur in Gregorian year. (let* ((jan1 (fixed-from-gregorian (gregorian-date january 1 g-year))) (dec31 (fixed-from-gregorian (gregorian-date december 31 g-year))) (y (standard-year (coptic-from-fixed jan1))) ;; The possible occurrences in one year are (date1 (fixed-from-coptic (coptic-date c-month c-day y))) (date2 (fixed-from-coptic (coptic-date c-month c-day (1+ y))))) (append (if ; date1 occurs in current year (<= jan1 date1 dec31) ;; Then that date; otherwise, none (list date1) nil) (if ; date2 occurs in current year (<= jan1 date2 dec31) ;; Then that date; otherwise, none (list date2) nil)))) **) CopticInGregorian[cMonth_, cDay_, gYear_] := Module[{jan1, dec31, y, date1, date2, result}, jan1 = ToFixed[Gregorian[January[], 1, gYear]]; dec31 = ToFixed[Gregorian[December[], 31, gYear]]; y = CYear[Coptic[jan1]]; date1 = ToFixed[Coptic[cMonth, cDay, y]]; date2 = ToFixed[Coptic[cMonth, cDay, y + 1]]; result = {}; If[LessEqual[jan1, date1, dec31], result = Append[result, date1]]; If[LessEqual[jan1, date2, dec31], result = Append[result, date2]]; result ] (** (defun coptic-christmas (g-year) ;; TYPE gregorian-year -> list-of-fixed-dates ;; List of zero or one fixed dates of Coptic Christmas ;; in Gregorian year. (coptic-in-gregorian 4 29 g-year)) **) CopticChristmas[gYear_] := CopticInGregorian[4, 29, gYear] (** ;;;; Section: Islamic Calendar **) (** (defconstant islamic-epoch ;; TYPE fixed-date ;; Fixed date of start of the Islamic calendar. (fixed-from-julian (julian-date july 16 (ce 622)))) **) IslamicEpoch[] = ToFixed[Julian[July[], 16, CE[622]]] (** (defun islamic-leap-year? (i-year) ;; TYPE islamic-year -> boolean ;; True if year is an Islamic leap year. (< (mod (+ 14 ( * 11 i-year)) 30) 11)) **) LeapYearQ[Islamic, year_] := Mod[11 year + 14, 30] < 11 (** (defun fixed-from-islamic (i-date) ;; TYPE islamic-date -> fixed-date ;; Fixed date equivalent to Islamic date. (let* ((month (standard-month i-date)) (day (standard-day i-date)) (year (standard-year i-date))) (+ day ; Days so far this month. (ceiling ; Days in prior months. ( * 29.5 (1- month))) ( * (1- year) 354) ; Nonleap days in prior years. (quotient ; Leap days in prior years. (+ 3 ( * 11 year)) 30) islamic-epoch -1))) ; Days before start of calendar. **) ToFixed[date_Islamic] := Module[{year}, year = CYear[date]; CDay[date] + Ceiling[29.5 (CMonth[date] - 1)] + (year - 1) 354 + Quotient[3 + 11 year, 30] + IslamicEpoch[] - 1 ] (** (defun islamic-from-fixed (date) ;; TYPE fixed-date -> islamic-date ;; Islamic date (month day year) corresponding to fixed ;; date. (let* ((year ; Divide elapsed days by average year length. (quotient (+ ( * 30 (- date islamic-epoch)) 10646) 10631)) (month ; Months alternate between 29 and 30 days (min 12 ; Last month can be longer (1+ (ceiling (/ (- date 29 (fixed-from-islamic (islamic-date 1 1 year))) 29.5))))) (day ; Calculate the day by subtraction. (1+ (- date (fixed-from-islamic (islamic-date month 1 year)))))) (islamic-date month day year))) **) Islamic[date_Integer] := Module[{year, month, day}, year = Quotient[30 (date - IslamicEpoch[]) + 10646, 10631]; month = Min[12, 1 + Ceiling[(date - 29 - ToFixed[Islamic[1, 1, year]]) / 29.5]]; day = 1 + date - ToFixed[Islamic[month, 1, year]]; Islamic[month, day, year] ] (** (defun islamic-in-gregorian (i-month i-day g-year) ;; TYPE (islamic-month islamic-day gregorian-year) ;; TYPE -> list-of-fixed-dates ;; List of the fixed dates of Islamic month, day ;; that occur in Gregorian year. (let* ((jan1 (fixed-from-gregorian (gregorian-date january 1 g-year))) (dec31 (fixed-from-gregorian (gregorian-date december 31 g-year))) (y (standard-year (islamic-from-fixed jan1))) ;; The possible occurrences in one year are (date1 (fixed-from-islamic (islamic-date i-month i-day y))) (date2 (fixed-from-islamic (islamic-date i-month i-day (1+ y)))) (date3 (fixed-from-islamic (islamic-date i-month i-day (+ 2 y))))) ;; Combine in one list those that occur in current year (append (if (<= jan1 date1 dec31) (list date1) nil) (if (<= jan1 date2 dec31) (list date2) nil) (if (<= jan1 date3 dec31) (list date3) nil)))) **) IslamicInGregorian[iMonth_, iDay_, gYear_] := Module[{jan1, dec31, y, date1, date2, date3, result}, jan1 = ToFixed[Gregorian[January[], 1, gYear]]; dec31 = ToFixed[Gregorian[December[], 31, gYear]]; y = CYear[Islamic[jan1]]; date1 = ToFixed[Islamic[iMonth, iDay, y]]; date2 = ToFixed[Islamic[iMonth, iDay, y + 1]]; date3 = ToFixed[Islamic[iMonth, iDay, y + 2]]; result = {}; If[LessEqual[jan1, date1, dec31], result = Append[result, date1]]; If[LessEqual[jan1, date2, dec31], result = Append[result, date2]]; If[LessEqual[jan1, date3, dec31], result = Append[result, date3]]; result ] (** (defun mawlid-an-nabi (g-year) ;; TYPE gregorian-year -> list-of-fixed-dates ;; List of fixed dates of Mawlid-an-Nabi occurring in ;; Gregorian year. (islamic-in-gregorian 3 12 g-year)) **) MawlidAnNabi[gYear_] := IslamicInGregorian[3, 12, gYear] (** ;;;; Section: Bahai Calendar **) (** (defconstant bahai-epoch ;; TYPE fixed-date ;; Fixed date of start of Bahai calendar. (fixed-from-gregorian (gregorian-date march 21 1844))) **) BahaiEpoch[] = ToFixed[Gregorian[March[], 21, 1844]] (** (defun fixed-from-bahai (b-date) ;; TYPE bahai-date -> fixed-date ;; Fixed date equivalent to the Bahai date b-date. (let* ((major (bahai-major b-date)) (cycle (bahai-cycle b-date)) (year (bahai-year b-date)) (month (bahai-month b-date)) (day (bahai-day b-date)) (g-year; Corresponding Gregorian year. (+ ( * 361 (1- major)) ( * 19 (1- cycle)) year -1 (gregorian-year-from-fixed bahai-epoch)))) (+ (fixed-from-gregorian ; Prior years. (gregorian-date march 20 g-year)) ( * 19 (1- month)) ; Elapsed months. ;; Subtract 14 or 15 if counted ayyam-i-ha. (if (/= month 20) 0 (if (gregorian-leap-year? (1+ g-year)) -14 -15)) day))) ; Days in current month. **) ToFixed[date_Bahai] := Module[{month, gYear}, month = CMonth[date]; gYear = 361 (CMajor[date] - 1) + 19 (CCycle[date] - 1) + CYear[date] - 1 + GregorianYearFromFixed[BahaiEpoch[]]; ToFixed[Gregorian[March[], 20, gYear]] + 19 (month - 1) + If[month =!= 20, 0, If[LeapYearQ[Gregorian, gYear + 1], -14, -15]] + CDay[date] ] (** (defun bahai-from-fixed (date) ;; TYPE fixed-date -> bahai-date ;; Bahai (month day cycle year) corresponding to fixed ;; date. (let* ((g-year (gregorian-year-from-fixed date)) (start ; 1844 (gregorian-year-from-fixed bahai-epoch)) (years ; Since start of Bahai calendar. (- g-year start (if (<= (fixed-from-gregorian (gregorian-date january 1 g-year)) date (fixed-from-gregorian (gregorian-date march 20 g-year))) 1 0))) (major (1+ (quotient years 361))) (cycle (1+ (quotient (mod years 361) 19))) (year (1+ (mod years 19))) (days; Since start of year (- date (fixed-from-bahai (bahai-date major cycle year 1 1)))) (month (if (>= date (fixed-from-bahai (bahai-date major cycle year 20 1))) 20 (1+ (quotient days 19)))) (day (- date -1 (fixed-from-bahai (bahai-date major cycle year month 1))))) (bahai-date major cycle year month day))) **) Bahai[date_Integer] := Module[{gYear, start, years, major, cycle, year, days, month, day}, gYear = GregorianYearFromFixed[date]; start = GregorianYearFromFixed[BahaiEpoch[]]; years = gYear - start - If[ToFixed[Gregorian[January[], 1, gYear]] <= date <= ToFixed[Gregorian[March[], 20, gYear]], 1, 0]; major = 1 + Quotient[years, 361]; cycle = 1 + Quotient[Mod[years, 361], 19]; year = 1 + Mod[years, 19]; days = date - ToFixed[Bahai[major, cycle, year, 1, 1]]; month = If[date >= ToFixed[Bahai[major, cycle, year, 20, 1]], 20, 1 + Quotient[days, 19]]; day = date + 1 - ToFixed[Bahai[major, cycle, year, month, 1]]; Bahai[major, cycle, year, month, day] ] (** (defun bahai-new-year (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Bahai New Year in Gregorian year. (fixed-from-gregorian (gregorian-date march 21 g-year))) **) BahaiNewYear[gYear_] := ToFixed[Gregorian[March[], 21, gYear]] (** (defun feast-of-ridvan (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Bahai New Year in Gregorian year. (let* ((years (- g-year (gregorian-year-from-fixed bahai-epoch))) (major (1+ (quotient years 361))) (cycle (1+ (quotient (mod years 361) 19))) (year (1+ (mod years 19)))) (fixed-from-bahai (bahai-date major cycle year 2 13)))) **) FeastOfRidvan[gYear_] := Module[{years, major, cycle, year}, years = gYear - GregorianYearFromFixed[BahaiEpoch[]]; major = 1 + Quotient[years, 361]; cycle = 1 + Quotient[Mod[years, 361], 19]; year = 1 + Mod[years, 19]; ToFixed[Bahai[major, cycle, year, 2, 13]] ] (** ;;;; Section: Persian Calendar **) (** (defun persian-leap-year? (p-year) ;; TYPE persian-year -> boolean ;; True if year is a leap year on the Persian calendar. (let* ((y ; Years since start of 2820-year cycles (if (< 0 p-year) (- p-year 474) (- p-year 473))); No year zero (year ; Equivalent year in the range 474...3263 (+ (mod y 2820) 474))) (< (mod ( * (+ year 38) 682) 2816) 682))) **) LeapYearQ[Persian, pYear_] := Module[{y, year}, y = If[0 < pYear, pYear - 474, pYear - 473]; year = Mod[y, 2820] + 474; Mod[(year + 38) 682, 2816] < 682 ] (** (defconstant persian-epoch ;; TYPE fixed-date ;; Fixed date of start of the Persian calendar. (fixed-from-julian (julian-date march 19 (ce 622)))) **) PersianEpoch[] = ToFixed[Julian[March[], 19, CE[622]]] (** (defun fixed-from-persian (p-date) ;; TYPE persian-date -> fixed-date ;; Fixed date equivalent to Persian date. (let* ((day (standard-day p-date)) (month (standard-month p-date)) (p-year (standard-year p-date)) (y ; Years since start of 2820-year cycle (if (< 0 p-year) (- p-year 474) (- p-year 473))); No year zero (year ; Equivalent year in the range 474...3263 (+ (mod y 2820) 474))) (+ (1- persian-epoch); Days before epoch ( * 1029983 ; Days in 2820-year cycles ; before Persian year 474 (quotient y 2820)) ( * 365 (1- year)) ; Nonleap days in prior years this ; 2820-year cycle (quotient ; Leap days in prior years this ; 2820-year cycle (- ( * 682 year) 110) 2816) (if (<= month 7) ; Days in prior months this year ( * 31 (1- month)) (+ ( * 30 (1- month)) 6)) day))) ; Days so far this month **) ToFixed[date_Persian] := Module[{day, month, pYear, y, year}, day = CDay[date]; month = CMonth[date]; pYear = CYear[date]; y = If[0 < pYear, pYear - 474, pYear - 473]; year = Mod[y, 2820] + 474; PersianEpoch[] - 1 + 1029983 Quotient[y, 2820] + 365 (year - 1) + Quotient[682 year - 110, 2816] + If[month <= 7, 31 (month - 1), 30 (month - 1) + 6] + day ] (** (defun persian-year-from-fixed (date) ;; TYPE fixed-date -> persian-year ;; Persian year corresponding to the fixed date. (let* ((d0 ; Prior days since start of 2820-year cycle ; beginning in Persian year 474 (- date (fixed-from-persian (persian-date 1 1 475)))) (n2820 ; Completed prior 2820-year cycles (quotient d0 1029983)) (d1 ; Prior days not in n2820--that is, days ; since start of last 2820-year cycle (mod d0 1029983)) (y2820 ; Years since start of last 2820-year cycle (if (= d1 1029982) ;; Last day of 2820-year cycle 2820 ;; Otherwise use cycle of years formula (quotient (+ ( * 2816 d1) 1031337) 1028522) ;; If ( * 2816 d1) causes integers that are ;; too-large, use instead: ;; (let ((a (floor d1 366)) ;; (b (mod d1 366))) ;; (+ 1 a (quotient ;; (+ ( * 2134 a) ( * 2816 b) 2815) ;; 1028522))) )) (year ; Years since Persian epoch (+ 474 ; Years before start of 2820-year cycles ( * 2820 n2820) ; Years in prior 2820-year cycles y2820))); Years since start of last 2820-year ; cycle (if (< 0 year) year (1- year)))); No year zero **) PersianYearFromFixed[date_] := Module[{d0, n2820, d1, y2820, year}, d0 = date - ToFixed[Persian[1, 1, 475]]; n2820 = Quotient[d0, 1029983]; d1 = Mod[d0, 1029983]; y2820 = If[d1 == 1029982, 2820, Quotient[2816 d1 + 1031337, 1028522]]; year = 474 + 2820 n2820 + y2820; If[0 < year, year, year - 1] ] (** (defun persian-from-fixed (date) ;; TYPE fixed-date -> persian-date ;; Persian (month day year) corresponding to fixed date. (let* ((year (persian-year-from-fixed date)) (day-of-year (1+ (- date (fixed-from-persian (persian-date 1 1 year))))) (month (if (<= day-of-year 186) (ceiling (/ day-of-year 31)) (ceiling (/ (- day-of-year 6) 30)))) (day ; Calculate the day by subtraction (- date (1- (fixed-from-persian (persian-date month 1 year)))))) (persian-date month day year))) **) Persian[date_Integer] := Module[{year, dayOfYear, month, day}, year = PersianYearFromFixed[date]; dayOfYear = 1 + date - ToFixed[Persian[1, 1, year]]; month = If[dayOfYear < 186, Ceiling[dayOfYear / 31], Ceiling[(dayOfYear - 6) / 30]]; day = date - (ToFixed[Persian[month, 1, year]] - 1); Persian[month, day, year] ] (** (defun naw-ruz (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Persian New Year (Naw-Ruz) in Gregorian ;; year. (let* ((persian-year (1+ (- g-year (gregorian-year-from-fixed persian-epoch))))) (fixed-from-persian (persian-date 1 1 (if (<= persian-year 0) ;; No Persian year 0 (1- persian-year) persian-year))))) **) NawRuz[gYear_] := Module[{persianYear}, persianYear = 1 + gYear - GregorianYearFromFixed[PersianEpoch[]]; ToFixed[Persian[1, 1, If[persianYear <= 0, persianYear - 1, persianYear]]] ] (** ;;;; Section: Hebrew Calendar **) (** (defconstant hebrew-epoch ;; TYPE fixed-date ;; Fixed date of start of the Hebrew calendar, that is, ;; Tishri 1, 1 AM. (fixed-from-julian (julian-date october 7 (bce 3761)))) **) HebrewEpoch[] = ToFixed[Julian[October[], 7, BCE[3761]]] (** (defun hebrew-leap-year? (h-year) ;; TYPE hebrew-year -> boolean ;; True if year is a leap year on Hebrew calendar. (< (mod (1+ ( * 7 h-year)) 19) 7)) **) LeapYearQ[Hebrew, hYear_] := Mod[1 + 7 hYear, 19] < 7 (** (defun last-month-of-hebrew-year (h-year) ;; TYPE hebrew-year -> hebrew-month ;; Last month of Hebrew year. (if (hebrew-leap-year? h-year) 13 12)) **) LastMonthOfHebrewYear[hYear_Integer] := If[LeapYearQ[Hebrew, hYear], 13, 12] (** (defun last-day-of-hebrew-month (h-month h-year) ;; TYPE (hebrew-month hebrew-year) -> hebrew-day ;; Last day of month in Hebrew year. (if (or (member h-month (list 2 4 6 10 13)) (and (= h-month 12) (not (hebrew-leap-year? h-year))) (and (= h-month 8) (not (long-heshvan? h-year))) (and (= h-month 9) (short-kislev? h-year))) 29 30)) **) LastDayOfHebrewMonth[hMonth_Integer, hYear_Integer] := If[MemberQ[{2, 4, 6, 10, 13}, hMonth] || ((hMonth == 12) && !LeapYearQ[Hebrew, hYear]) || ((hMonth == 8) && !LongHeshvanQ[hYear]) || ((hMonth == 9) && ShortKislevQ[hYear]), 29, 30] (** (defun hebrew-calendar-elapsed-days (h-year) ;; TYPE hebrew-year -> integer ;; Number of days elapsed from the (Sunday) noon prior ;; to the epoch of the Hebrew calendar to the mean ;; conjunction (molad) of Tishri of Hebrew year h-year, ;; or one day later. (let* ((months-elapsed ; Since start of Hebrew calendar. (quotient (- ( * 235 h-year) 234) 19)) (parts-elapsed; Fractions of days since prior noon. (+ 12084 ( * 13753 months-elapsed))) (day ; Whole days since prior noon. (+ ( * 29 months-elapsed) (quotient parts-elapsed 25920))) ;; If ( * 13753 months-elapsed) causes integers that ;; are to large, use instead: ;; (parts-elapsed ;; (+ 204 ( * 793 (mod months-elapsed 1080)))) ;; (hours-elapsed ;; (+ 11 ( * 12 months-elapsed) ;; ( * 793 (quotient months-elapsed 1080)) ;; (quotient parts-elapsed 1080))) ;; (day ;; (+ ( * 29 months-elapsed) ;; (quotient hours-elapsed 24))) ) (if (< (mod ( * 3 (1+ day)) 7) 3); Sun, Wed, or Fri (1+ day) ; Delay one day. day))) **) HebrewCalendarElapsedDays[hYear_Integer] := Module[{monthsElapsed, partsElapsed, day}, monthsElapsed = Quotient[235 hYear - 234, 19]; partsElapsed = 12084 + 13753 monthsElapsed; day = 29 monthsElapsed + Quotient[partsElapsed, 25920]; If[Mod[3 (day + 1), 7] < 3, day + 1, day] ] (** (defun hebrew-new-year-delay (h-year) ;; TYPE hebrew-year -> {0,1,2} ;; Delays to start of Hebrew year to keep ordinary year in ;; range 353-356 and leap year in range 383-386. (let* ((ny0 (hebrew-calendar-elapsed-days (1- h-year))) (ny1 (hebrew-calendar-elapsed-days h-year)) (ny2 (hebrew-calendar-elapsed-days (1+ h-year)))) (cond ((= (- ny2 ny1) 356) 2); Next year would be too long. ((= (- ny1 ny0) 382) 1); Previous year too short. (t 0)))) **) HebrewNewYearDelay[hYear_Integer] := Module[{ny0, ny1, ny2}, ny0 = HebrewCalendarElapsedDays[hYear - 1]; ny1 = HebrewCalendarElapsedDays[hYear]; ny2 = HebrewCalendarElapsedDays[hYear + 1]; Which[ny2 - ny1 == 356, 2, ny1 - ny0 == 382, 1, True, 0] ] (** (defun days-in-hebrew-year (h-year) ;; TYPE hebrew-year -> {353,354,355,383,384,385} ;; Number of days in Hebrew year. Calls fixed-from-hebrew ;; for value that does not in turn require ;; days-in-hebrew-year. (- (fixed-from-hebrew (hebrew-date 7 1 (1+ h-year))) (fixed-from-hebrew (hebrew-date 7 1 h-year)))) **) DaysInHebrewYear[hYear_Integer] := ToFixed[Hebrew[7, 1, hYear + 1]] - ToFixed[Hebrew[7, 1, hYear]]; (** (defun long-heshvan? (h-year) ;; TYPE hebrew-year -> boolean ;; True if Heshvan is long in Hebrew year. (= (mod (days-in-hebrew-year h-year) 10) 5)) **) LongHeshvanQ[hYear_Integer] := Mod[DaysInHebrewYear[hYear], 10] == 5 (** (defun short-kislev? (h-year) ;; TYPE hebrew-year -> boolean ;; True if Kislev is short in Hebrew year. (= (mod (days-in-hebrew-year h-year) 10) 3)) **) ShortKislevQ[hYear_Integer] := Mod[DaysInHebrewYear[hYear], 10] == 3 (** (defun fixed-from-hebrew (h-date) ;; TYPE hebrew-date -> fixed-date ;; Fixed date of Hebrew date. This function is designed ;; so that it works for Hebrew dates month, day, year even ;; if the month has fewer than day days--in that case the ;; function returns the (day-1)st day after month 1, year. ;; This property is required by the functions ;; hebrew-birthday and yahrzeit. (let* ((month (standard-month h-date)) (day (standard-day h-date)) (year (standard-year h-date))) (+ hebrew-epoch ; Days before fixed date 1. (hebrew-calendar-elapsed-days; Days in prior years. year) (hebrew-new-year-delay year) day -1 ; Days so far this month. (if ;; before Tishri (< month 7) ;; Then add days in prior months this year before ;; and after Nisan. (+ (sum (last-day-of-hebrew-month m year) m 7 (<= m (last-month-of-hebrew-year year))) (sum (last-day-of-hebrew-month m year) m 1 (< m month))) ;; Else add days in prior months this year (sum (last-day-of-hebrew-month m year) m 7 (< m month)))))) **) ToFixed[date_Hebrew] := Module[{month, day, year}, month = CMonth[date]; day = CDay[date]; year = CYear[date]; HebrewEpoch[] + HebrewCalendarElapsedDays[year] + HebrewNewYearDelay[year] + day - 1 + If[month < 7, MSum[(LastDayOfHebrewMonth[#, year])&, 7, (# <= LastMonthOfHebrewYear[year])&] + MSum[(LastDayOfHebrewMonth[#, year])&, 1, (# < month)&], MSum[(LastDayOfHebrewMonth[#, year])&, 7, (# < month)&]] ] (** (defun hebrew-from-fixed (date) ;; TYPE fixed-date -> hebrew-date ;; Hebrew (month day year) corresponding to fixed date. ;; The fraction can be approximated by 365.25. (let* ((approx ; Approximate year (may be off by 1) (quotient (- date hebrew-epoch) 35975351/98496)) ;; The value 35975351/98496, the average length of ;; a Hebrew year, can be approximated by 365.25 (year ; Search forward. (+ approx -1 ; Lower bound. (sum 1 y approx (>= date (fixed-from-hebrew (hebrew-date 7 1 y)))))) (start ; Starting month for search for month. (if (< date (fixed-from-hebrew (hebrew-date 1 1 year))) 7 ; Tishri 1)) ; Nisan (month ; Search forward from either Tishri or Nisan. (+ start (sum 1 m start (> date (fixed-from-hebrew (hebrew-date m (last-day-of-hebrew-month m year) year)))))) (day ; Calculate the day by subtraction. (1+ (- date (fixed-from-hebrew (hebrew-date month 1 year)))))) (hebrew-date month day year))) **) Hebrew[date_Integer] := Module[{approx, year, start, month, day}, approx = Quotient[date - HebrewEpoch[], 35975351/98496]; year = approx - 1 + MSum[(1)&, approx, (date >= ToFixed[Hebrew[7, 1, #]])&]; start = If[date < ToFixed[Hebrew[1, 1, year]], 7, 1]; month = start + MSum[(1)&, start, (date > ToFixed[Hebrew[#, LastDayOfHebrewMonth[#, year], year]])&]; day = 1 + date - ToFixed[Hebrew[month, 1, year]]; Hebrew[month, day, year] ] (** (defun yom-kippur (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Yom Kippur occurring in Gregorian year. (let* ((hebrew-year (1+ (- g-year (gregorian-year-from-fixed hebrew-epoch))))) (fixed-from-hebrew (hebrew-date 7 10 hebrew-year)))) **) YomKippur[gYear_Integer] := Module[{hebrewYear}, hebrewYear = 1 + gYear - GregorianYearFromFixed[HebrewEpoch[]]; ToFixed[Hebrew[7, 10, hebrewYear]] ] (** (defun passover (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Passover occurring in Gregorian year. (let* ((hebrew-year (- g-year (gregorian-year-from-fixed hebrew-epoch)))) (fixed-from-hebrew (hebrew-date 1 15 hebrew-year)))) **) Passover[gYear_Integer] := Module[{hebrewYear}, hebrewYear = gYear - GregorianYearFromFixed[HebrewEpoch[]]; ToFixed[Hebrew[1, 15, hebrewYear]] ] (** (defun omer (date) ;; TYPE fixed-date -> omer-count ;; Number of elapsed weeks and days in the omer at date. ;; Returns bogus if that date does not fall during the ;; omer. (let* ((c (- date (fixed-from-hebrew (hebrew-date 1 15 (standard-year (hebrew-from-fixed date))))))) (if (<= 1 c 49) (list (quotient c 7) (mod c 7)) bogus))) **) Omer[date_Integer] := Module[{c}, c = date - ToFixed[Hebrew[1, 15, CYear[Hebrew[date]]]]; If[1 <= c <= 49, {Quotient[c, 7], Mod[c, 7]}, Bogus] ] (** (defun purim (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Purim occurring in Gregorian year. (let* ((hebrew-year (- g-year (gregorian-year-from-fixed hebrew-epoch))) (last-month ; Adar or Adar II (last-month-of-hebrew-year hebrew-year))) (fixed-from-hebrew (hebrew-date last-month 14 hebrew-year)))) **) Purim[gYear_Integer] := Module[{hebrewYear, lastMonth}, hebrewYear = gYear - GregorianYearFromFixed[HebrewEpoch[]]; lastMonth = LastMonthOfHebrewYear[hebrewYear]; ToFixed[Hebrew[lastMonth, 14, hebrewYear]] ] (** (defun ta-anith-esther (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Ta'anith Esther occurring in ;; Gregorian year. (let* ((purim-date (purim g-year))) (if ; Purim is on Sunday (= (day-of-week-from-fixed purim-date) sunday) ;; Then prior Thursday (- purim-date 3) ;; Else previous day (1- purim-date)))) **) TaAnithEsther[gYear_Integer] := Module[{purimDate}, purimDate = Purim[gYear]; If[DayOfWeekFromFixed[purimDate] == Sunday[], purimDate - 3, purimDate - 1] ] (** (defun tisha-b-av (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Tisha B'Av occurring in Gregorian year. (let* ((hebrew-year (- g-year (gregorian-year-from-fixed hebrew-epoch))) (ninth-of-av (fixed-from-hebrew (hebrew-date 5 9 hebrew-year)))) (if ; Ninth of Av is Saturday (= (day-of-week-from-fixed ninth-of-av) saturday) ;; Then the next day (1+ ninth-of-av) ninth-of-av))) **) TishaBAv[gYear_Integer] := Module[{hebrewYear, ninthOfAv}, hebrewYear = gYear - GregorianYearFromFixed[HebrewEpoch[]]; ninthOfAv = ToFixed[Hebrew[5, 9, hebrewYear]]; If[DayOfWeekFromFixed[ninthOfAv] == Saturday[], ninthOfAv + 1, ninthOfAv] ] (** (defun birkath-ha-hama (g-year) ;; TYPE gregorian-year -> list-of-fixed-dates ;; List of fixed date of Birkath HaHama occurring in ;; Gregorian year, if it occurs. (let* ((mar26 (julian-in-gregorian march 26 g-year))) (if (and (not (equal mar26 nil)) (= (mod (standard-year (julian-from-fixed (first mar26))) 28) 21)) mar26 nil))) **) BirkathHaHama[gYear_Integer] := Module[{mar26}, mar26 = JulianInGregorian[March[], 26, gYear]; If[mar26 =!= {} && Mod[CYear[Julian[First[mar26]]], 28] == 21, mar26, {}] ] (** (defun sh-ela (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Sh'ela occurring in Gregorian year. (- (first (julian-in-gregorian march 26 (1+ g-year))) 124)) **) ShEla[gYear_Integer] := First[JulianInGregorian[March[], 26, gYear + 1]] - 124 (** (defun yom-ha-zikaron (g-year) ;; TYPE gregorian-year -> fixed-date ;; Fixed date of Yom HaZikaron occurring in Gregorian year. (let* ((hebrew-year (- g-year (gregorian-year-from-fixed hebrew-epoch))) (h; Ordinarily Iyar 4 (fixed-from-hebrew (hebrew-date 2 4 hebrew-year)))) (if (< wednesday (day-of-week-from-fixed h)) ;; But prior Wednesday if Iyar 5 is Friday or ;; Saturday (kday-before h wednesday) h))) **) YomHaZikaron[gYear_Integer] := Module[{hebrewYear, h}, hebrewYear = gYear - GregorianYearFromFixed[HebrewEpoch[]]; h = ToFixed[Hebrew[2, 4, hebrewYear]]; If[Wednesday[] < DayOfWeekFromFixed[h], KDayBefore[h, Wednesday[]], h] ] (** (defun hebrew-birthday (birthdate h-year) ;; TYPE (hebrew-date hebrew-year) -> fixed-date ;; Fixed date of the anniversary of Hebrew birthdate ;; occurring in Hebrew year. This function assumes ;; that the function fixed-from-hebrew works for Hebrew ;; dates month, day, year even if the month has fewer than ;; day days--in that case the function returns the ;; (day-1)st day after month 1, year. (let* ((birth-day (standard-day birthdate)) (birth-month (standard-month birthdate)) (birth-year (standard-year birthdate))) (if ; It's Adar in a normal Hebrew year or Adar II ; in a Hebrew leap year, (= birth-month (last-month-of-hebrew-year birth-year)) ;; Then use the same day in last month of Hebrew year. (fixed-from-hebrew (hebrew-date (last-month-of-hebrew-year h-year) birth-day h-year)) ;; Else use the normal anniversary of the birth date, ;; or the corresponding day in years without that date (fixed-from-hebrew (hebrew-date birth-month birth-day h-year))))) **) HebrewBirthday[birthDate_Hebrew, hYear_Integer] := Module[{birthDay, birthMonth, birthYear}, birthDay = CDay[birthDate]; birthMonth = CMonth[birthDate]; birthYear = CYear[birthDate]; If[birthMonth == LastMonthOfHebrewYear[birthYear], ToFixed[Hebrew[LastMonthOfHebrewYear[hYear], birthDay, hYear]], ToFixed[Hebrew[birthMonth, birthDay, hYear]]] ] (** (defun yahrzeit (death-date h-year) ;; TYPE (hebrew-date hebrew-year) -> fixed-date ;; Fixed date of the anniversary of Hebrew death-date ;; occurring in Hebrew year. This function assumes ;; that the function fixed-from-hebrew works for Hebrew ;; dates month, day, year even if the month has fewer than ;; day days--in that case the function returns the ;; (day-1)st day after month 1, year. (let* ((death-day (standard-day death-date)) (death-month (standard-month death-date)) (death-year (standard-year death-date))) (cond ;; If it's Heshvan 30 it depends on the first ;; anniversary; if that was not Heshvan 30, use ;; the day before Kislev 1. ((and (= death-month 8) (= death-day 30) (not (long-heshvan? (1+ death-year)))) (1- (fixed-from-hebrew (hebrew-date 9 1 h-year)))) ;; If it's Kislev 30 it depends on the first ;; anniversary; if that was not Kislev 30, use ;; the day before Teveth 1. ((and (= death-month 9) (= death-day 30) (short-kislev? (1+ death-year))) (1- (fixed-from-hebrew (hebrew-date 10 1 h-year)))) ;; If it's Adar II, use the same day in last ;; month of Hebrew year (Adar or Adar II). ((= death-month 13) (fixed-from-hebrew (hebrew-date (last-month-of-hebrew-year h-year) death-day h-year))) ;; If it's the 30th in Adar I and Hebrew year is not a ;; Hebrew leap year (so Adar has only 29 days), use the ;; last day in Shevat. ((and (= death-day 30) (= death-month 12) (not (hebrew-leap-year? h-year))) (fixed-from-hebrew (hebrew-date 11 30 h-year))) ;; In all other cases, use the normal anniversary of ;; the date of death. (t (fixed-from-hebrew (hebrew-date death-month death-day h-year)))))) **) Yahrzeit[deathDate_Hebrew, hYear_Integer] := Module[{deathDay, deathMonth, deathYear}, deathDay = CDay[deathDate]; deathMonth = CMonth[deathDate]; deathYear = CMonth[deathDate]; Which[ deathMonth == 8 && deathDay == 30 && !LongHeshvanQ[deathYear + 1], 1 - ToFixed[Hebrew[9, 1, hYear]], deathMonth == 9 && deathDay == 30 && ShortKislevQ[deathYear + 1], 1 - ToFixed[Hebrew[10, 1, hYear]], deathMonth == 13, ToFixed[Hebrew[LastMonthOfHebrewYear[hYear], deathDay, hYear]], deathDay == 30 && deathMonth == 12 && !LeapYearQ[Hebrew, hYear], ToFixed[Hebrew[11, 30, hYear]], True, ToFixed[Hebrew[deathMonth, deathDay, hYear]] ] ] (** ;;;; Section: Mayan Calendars **) (** (defconstant mayan-epoch ;; TYPE fixed-date ;; Fixed date of start of the Mayan calendar, according ;; to the Goodman-Martinez-Thompson correlation. ;; That is, August 11, -3113. (fixed-from-jd 584282.5)) **) MayanEpoch[] = FixedFromJD[584282.5] (** (defun fixed-from-mayan-long-count (count) ;; TYPE mayan-long-count-date -> fixed-date ;; Fixed date corresponding to the Mayan long count ;; count, which is a list (baktun katun tun uinal kin). (let* ((baktun (mayan-baktun count)) (katun (mayan-katun count)) (tun (mayan-tun count)) (uinal (mayan-uinal count)) (kin (mayan-kin count))) (+ mayan-epoch ; Fixed date at Mayan 0.0.0.0.0 ( * baktun 144000); Baktun. ( * katun 7200) ; Katun. ( * tun 360) ; Tun. ( * uinal 20) ; Uinal. kin))) ; Kin (days). **) ToFixed[date_MayanLongCount] := MayanEpoch[] + CBaktun[date] 144000 + CKatun[date] 7200 + CTun[date] 360 + CUinal[date] 20 + CKin[date] (** (defun mayan-long-count-from-fixed (date) ;; TYPE fixed-date -> mayan-long-count-date ;; Mayan long count date of fixed date. (let* ((long-count (- date mayan-epoch)) (baktun (quotient long-count 144000)) (day-of-baktun (mod long-count 144000)) (katun (quotient day-of-baktun 7200)) (day-of-katun (mod day-of-baktun 7200)) (tun (quotient day-of-katun 360)) (day-of-tun (mod day-of-katun 360)) (uinal (quotient day-of-tun 20)) (kin (mod day-of-tun 20))) (mayan-long-count-date baktun katun tun uinal kin))) **) MayanLongCount[date_Integer] := Module[{longCount, baktun, dayOfBaktun, katun, dayOfKatun, tun, dayOfTun, uinal, kin}, longCount = date - MayanEpoch[]; baktun = Quotient[longCount, 144000]; dayOfBaktun = Mod[longCount, 144000]; katun = Quotient[dayOfBaktun, 7200]; dayOfKatun = Mod[dayOfBaktun, 7200]; tun = Quotient[dayOfKatun, 360]; dayOfTun = Mod[dayOfKatun, 360]; uinal = Quotient[dayOfTun, 20]; kin = Mod[dayOfTun, 20]; MayanLongCount[baktun, katun, tun, uinal, kin] ] (** (defconstant mayan-haab-at-epoch ;; TYPE mayan-haab-date ;; Haab date at long count 0.0.0.0.0. (mayan-haab-date 8 18)) **) MayanHaabAtEpoch[] = MayanHaab[8, 18] (** (defun mayan-haab-from-fixed (date) ;; TYPE fixed-date -> mayan-haab-date ;; Mayan haab date of fixed date. (let* ((long-count (- date mayan-epoch)) (day-of-haab (mod (+ long-count (mayan-haab-day mayan-haab-at-epoch) ( * 20 (1- (mayan-haab-month mayan-haab-at-epoch)))) 365)) (day (mod day-of-haab 20)) (month (1+ (quotient day-of-haab 20)))) (mayan-haab-date day month))) **) MayanHaab[date_Integer] := Module[{longCount, dayOfHaab, day, month}, longCount = date - MayanEpoch[]; dayOfHaab = Mod[longCount + CDay[MayanHaabAtEpoch[]] + 20 (CMonth[MayanHaabAtEpoch[]] - 1), 365]; day = Mod[dayOfHaab, 20]; month = 1 + Quotient[dayOfHaab, 20]; MayanHaab[day, month] ] (** (defun mayan-haab-difference (h-date1 h-date2) ;; TYPE (mayan-haab-date mayan-haab-date) -> integer ;; Number of days from Mayan haab date h-date1 to the next ;; occurrence of Mayan haab date h-date2. (let* ((day1 (mayan-haab-day h-date1)) (day2 (mayan-haab-day h-date2)) (month1 (mayan-haab-month h-date1)) (month2 (mayan-haab-month h-date2))) (mod (+ ( * 20 (- month2 month1)) (- day2 day1)) 365))) **) MayanHaabDifference[hDate1_MayanHaab, hDate2_MayanHaab] := Mod[20 (CMonth[hDate2] - CMonth[hDate1]) + (CDay[hDate2] - CDay[hDate1]), 365] (** (defun mayan-haab-on-or-before (haab date) ;; TYPE (mayan-haab-date fixed-date) -> fixed-date ;; Fixed date of latest date on or before fixed date ;; that is Mayan haab date haab. (- date (mod (- date (mayan-haab-difference (mayan-haab-from-fixed 0) haab)) 365))) **) MayanHaabOnOrBefore[haab_MayanHaab, date_Integer] := date - Mod[date - MayanHaabDifference[MayanHaab[0], haab], 365] (** (defconstant mayan-tzolkin-at-epoch ;; TYPE mayan-tzolkin-date ;; Tzolkin date at long count 0.0.0.0.0. (mayan-tzolkin-date 4 20)) **) MayanTzolkinAtEpoch[] = MayanTzolkin[4, 20] (** (defun mayan-tzolkin-from-fixed (date) ;; TYPE fixed-date -> mayan-tzolkin-date ;; Mayan tzolkin date of fixed date. (let* ((long-count (- date mayan-epoch)) (number (adjusted-mod (+ long-count (mayan-tzolkin-number mayan-tzolkin-at-epoch)) 13)) (name (adjusted-mod (+ long-count (mayan-tzolkin-name mayan-tzolkin-at-epoch)) 20))) (mayan-tzolkin-date number name))) **) MayanTzolkin[date_Integer] := Module[{longCount, number, name}, longCount = date - MayanEpoch[]; number = AdjustedMod[longCount + CNumber[MayanTzolkinAtEpoch[]], 13]; name = AdjustedMod[longCount + CName[MayanTzolkinAtEpoch[]], 20]; MayanTzolkin[number, name] ] (** (defun mayan-tzolkin-difference (t-date1 t-date2) ;; TYPE (mayan-tzolkin-date mayan-tzolkin-date) -> integer ;; Number of days from Mayan tzolkin date t-date1 to the ;; next occurrence of Mayan tzolkin date t-date2. (let* ((number1 (mayan-tzolkin-number t-date1)) (number2 (mayan-tzolkin-number t-date2)) (name1 (mayan-tzolkin-name t-date1)) (name2 (mayan-tzolkin-name t-date2)) (number-difference (- number2 number1)) (name-difference (- name2 name1))) (mod (+ number-difference ( * 13 (mod ( * 3 (- number-difference name-difference)) 20))) 260))) **) MayanTzolkinDifference[date1_MayanTzolkin, date2_MayanTzolkin] := Module[{numberDifference, nameDifference}, numberDifference = CNumber[date2] - CNumber[date1]; nameDifference = CName[date2] - CName[date1]; Mod[numberDifference + 13 Mod[3 (numberDifference - nameDifference), 20], 260] ] (** (defun mayan-tzolkin-on-or-before (tzolkin date) ;; TYPE (mayan-tzolkin-date fixed-date) -> fixed-date ;; Fixed date of latest date on or before fixed date ;; that is Mayan tzolkin date tzolkin. (- date (mod (- date (mayan-tzolkin-difference (mayan-tzolkin-from-fixed 0) tzolkin)) 260))) **) MayanTzolkinOnOrBefore[tzolkin_MayanTzolkin, date_Integer] := date - Mod[date - MayanTzolkinDifference[MayanTzolkin[0], tzolkin], 260] (** (defun mayan-haab-tzolkin-on-or-before (haab tzolkin date) ;; TYPE (mayan-haab-date mayan-tzolkin-date fixed-date) ;; TYPE -> fixed-date ;; Fixed date of latest date on or before date ;; that is Mayan haab date haab and tzolkin date tzolkin; ;; returns bogus if such a haab-tzolkin combination is ;; impossible. (let* ((haab-difference (mayan-haab-difference (mayan-haab-from-fixed 0) haab)) (tzolkin-difference (mayan-tzolkin-difference (mayan-tzolkin-from-fixed 0) tzolkin)) (diff (- tzolkin-difference haab-difference))) (if (= (mod diff 5) 0) (- date (mod (- date (+ haab-difference ( * 365 diff))) 18980)) bogus))); haab-tzolkin combination is impossible. **) MayanHaabTzolkinOnOrBefore[haab_MayanHaab, tzolkin_MayanTzolkin, date_Integer] := Module[{haabDifference, tzolkinDifference, diff}, haabDifference = MayanHaabDifference[MayanHaab[0], haab]; tzolkinDifference = MayanTzolkinDifference[MayanTzolkin[0], tzolkin]; diff = tzolkinDifference - haabDifference; If[Mod[diff, 5] == 0, date - Mod[date - (haabDifference + 365 diff), 18980], Bogus] ] (** ;;;; Section: Old Hindu Calendars **) (** (defconstant hindu-epoch ;; TYPE fixed-date ;; Fixed date of start of the Hindu calendar (Kali Yuga). (fixed-from-julian (julian-date february 18 (bce 3102)))) **) HinduEpoch[] = ToFixed[Julian[February[], 18, BCE[3102]]] (** (defun hindu-day-count (date) ;; TYPE fixed-date -> integer ;; Elapsed days (Ahargana) to date since Hindu epoch (K.Y.). (- date hindu-epoch)) **) HinduDayCount[date_] := date - HinduEpoch[] (** (defconstant arya-sidereal-year ;; TYPE rational ;; Length of Old Hindu solar year. 1577917500/4320000) **) AryaSiderealYear[] = 1577917500/4320000 (** (defconstant arya-solar-month ;; TYPE rational ;; Length of Old Hindu solar month. (/ arya-sidereal-year 12)) **) AryaSolarMonth[] = AryaSiderealYear[] / 12 (** (defun old-hindu-solar-from-fixed (date) ;; TYPE fixed-date -> hindu-solar-date ;; Old Hindu solar date equivalent to fixed date. (let* ((rise ; Sunrise on Hindu date. (+ (hindu-day-count date) 1/4)) (year ; Elapsed years. (quotient rise arya-sidereal-year)) (month (1+ (mod (quotient rise arya-solar-month) 12))) (day (1+ (floor (mod rise arya-solar-month))))) (hindu-solar-date month day year))) **) OldHinduSolar[date_Integer] := Module[{rise, year, month, day}, rise = HinduDayCount[date] + 1/4; year = Quotient[rise, AryaSiderealYear[]]; month = 1 + Mod[Quotient[rise, AryaSolarMonth[]], 12]; day = 1 + Floor[Mod[rise, AryaSolarMonth[]]]; OldHinduSolar[month, day, year] ] (** (defun fixed-from-old-hindu-solar (s-date) ;; TYPE hindu-solar-date -> fixed-date ;; Fixed date corresponding to Old Hindu solar date. (let* ((month (standard-month s-date)) (day (standard-day s-date)) (year (standard-year s-date))) (floor (+ hindu-epoch ; Since start of era. ( * year arya-sidereal-year) ; Days in elapsed years ( * (1- month) arya-solar-month) ; ...in months. day -1/4)))) ; Midnight of day. **) ToFixed[date_OldHinduSolar] := Floor[ HinduEpoch[] + CYear[date] AryaSiderealYear[] + (CMonth[date] - 1) AryaSolarMonth[] + CDay[date] - 1/4 ] (** (defconstant arya-lunar-month ;; TYPE rational ;; Length of Old Hindu lunar month. 1577917500/53433336) **) AryaLunarMonth[] = 1577917500/53433336 (** (defconstant arya-lunar-day ;; TYPE rational ;; Length of Old Hindu lunar day. (/ arya-lunar-month 30)) **) AryaLunarDay[] = AryaLunarMonth[] / 30 (** (defun old-hindu-lunar-leap-year? (l-year) ;; TYPE old-hindu-lunar-year -> boolean ;; True if year is a leap year on the ;; old Hindu calendar. (>= (mod (- ( * l-year arya-sidereal-year) arya-solar-month) arya-lunar-month) (- arya-lunar-month (mod arya-sidereal-year arya-lunar-month)))) **) LeapYearQ[OldHinduLunar, lYear_] := Mod[lYear AryaSiderealYear[] - AryaSolarMonth[], AryaLunarMonth[]] >= AryaLunarMonth[] - Mod[AryaSiderealYear[], AryaLunarMonth[]] (** (defun old-hindu-lunar-from-fixed (date) ;; TYPE fixed-date -> old-hindu-lunar-date ;; Old Hindu lunar date equivalent to fixed date. (let* ((rise ; Sunrise on Hindu date. (+ (hindu-day-count date) 1/4)) (new-moon ; Beginning of lunar month. (- rise (mod rise arya-lunar-month))) (leap ; If lunar contained in solar. (and (>= (- arya-solar-month arya-lunar-month) (mod new-moon arya-solar-month)) (> (mod new-moon arya-solar-month) 0))) (month ; Next solar month's name. (1+ (mod (ceiling (/ new-moon arya-solar-month)) 12))) (day ; Lunar days since beginning of lunar month. (1+ (mod (quotient rise arya-lunar-day) 30))) (year ; Solar year at end of lunar month(s). (1- (ceiling (/ (+ new-moon arya-solar-month) arya-sidereal-year))))) (old-hindu-lunar-date month leap day year))) **) OldHinduLunar[date_Integer] := Module[{rise, newMoon, leap, month, day, year}, rise = HinduDayCount[date] + 1/4; newMoon = rise - Mod[rise, AryaLunarMonth[]]; leap = AryaSolarMonth[] - AryaLunarMonth[] >= Mod[newMoon, AryaSolarMonth[]] && Mod[newMoon, AryaSolarMonth[]] > 0; month = 1 + Mod[Ceiling[newMoon / AryaSolarMonth[]], 12]; day = 1 + Mod[Quotient[rise, AryaLunarDay[]], 30]; year = Ceiling[(newMoon + AryaSolarMonth[]) / AryaSiderealYear[]] - 1; OldHinduLunar[month, leap, day, year] ] (** (defun fixed-from-old-hindu-lunar (l-date) ;; TYPE old-hindu-lunar-date -> fixed-date ;; Fixed date corresponding to Old Hindu lunar date. (let* ((year (old-hindu-lunar-year l-date)) (month (old-hindu-lunar-month l-date)) (leap (old-hindu-lunar-leap l-date)) (day (old-hindu-lunar-day l-date)) (mina ; One solar month before solar new year. ( * (1- ( * 12 year)) arya-solar-month)) (lunar-new-year ; New moon after mina. ( * arya-lunar-month (1+ (quotient mina arya-lunar-month))))) (floor (+ hindu-epoch lunar-new-year ( * arya-lunar-month (if ; If there was a leap month this year. (and (not leap) (<= (ceiling (/ (- lunar-new-year mina) (- arya-solar-month arya-lunar-month))) month)) month (1- month))) ( * (1- day) arya-lunar-day) ; Lunar days. 3/4)))) ; Add one if lunar day begins after sunrise. **) ToFixed[date_OldHinduLunar] := Module[{month, mina, lunarNewYear}, month = CMonth[date]; mina = (12 CYear[date] - 1) AryaSolarMonth[]; lunarNewYear = AryaLunarMonth[] (Quotient[mina, AryaLunarMonth[]] + 1); Floor[ HinduEpoch[] + lunarNewYear + AryaLunarMonth[] If[!CLeap[date] && Ceiling[(lunarNewYear - mina) / (AryaSolarMonth[] - AryaLunarMonth[])] <= month, month, month - 1] + (CDay[date] - 1) AryaLunarDay[] + 3/4 ] ] (** (defconstant arya-jovian-period ;; TYPE rational ;; Number of days in one revolution of Jupiter around the ;; Sun. 1577917500/364224) **) AryaJovianPeriod[] = 1577917500/364224 (** (defun jovian-year (date) ;; TYPE fixed-date -> {1-60} ;; Year of Jupiter cycle at fixed date. (1+ (mod (quotient (hindu-day-count date) (/ arya-jovian-period 12)) 60))) **) JovianYear[date_Integer] := Mod[Quotient[HinduDayCount[date], AryaJovianPeriod[] / 12], 60] + 1 (** ;;;; Section: Time and Astronomy **) (** (defun time-from-moment (moment) ;; TYPE moment -> (hour minute second) ;; Time of day (hour minute second) from moment moment. (let* ((hour (floor (mod ( * moment 24) 24))) (minute (floor (mod ( * moment 24 60) 60))) (second (double-float (mod ( * moment 24 60 60) 60)))) (time-of-day hour minute second))) **) TimeOfDay[moment_] := Module[{hour, minute, second}, hour = Floor[Mod[moment 24, 24]]; minute = Floor[Mod[moment 24 60, 60]]; second = Mod[moment 24 60 60, 60]; TimeOfDay[hour, minute, second] ] (* ADDED *) ToMoment[time_TimeOfDay] := CHour[time] / 24 + CMinute[time] / (24 60) + CSecond[time] / (24 60 60) (** (defun local-from-universal (u-time zone) ;; TYPE (moment minute) -> moment ;; Local time from u-time in universal time at time-zone ;; zone. (+ u-time (/ zone 24d0 60d0))) **) LocalFromUniversal[uTime_, zone_] := uTime + zone / (24 60) (** (defun universal-from-local (l-time zone) ;; TYPE (moment minute) -> moment ;; Universal time from l-time in local time at time-zone ;; zone. (- l-time (/ zone 24d0 60d0))) **) UniversalFromLocal[lTime_, zone_] := lTime - zone / (24 60) (** (defun location-offset (longitude zone) ;; TYPE (angle minute) -> minute ;; Offset of location at longitude ;; from standard time at zone. (- ( * 4 longitude) zone)) **) LocationOffset[longitude_, zone_] := 4 longitude - zone (** (defun local-from-standard (s-time offset) ;; TYPE (moment minute) -> moment ;; Local time from standard s-time at distance ;; offset (in minutes) from time zone. (+ s-time (/ offset 24d0 60d0))) **) LocalFromStandard[sTime_, offset_] := sTime + offset / (24 60) (** (defun standard-from-local (l-time offset) ;; TYPE (moment minute) -> moment ;; Standard time from local l-time at distance ;; offset (in minutes) from time zone. (- l-time (/ offset 24d0 60d0))) **) StandardFromLocal[lTime_, offset_] := lTime - offset / (24 60) (** (defun degrees (theta) ;; TYPE real -> angle ;; Normalize angle theta to range 0-360 degrees. (mod theta 360)) **) Degrees[theta_] := Mod[theta, 360] (** (defun radians-to-degrees (theta) ;; TYPE radian -> angle ;; Convert angle theta from radians to degrees. (degrees (/ theta pi 1/180))) **) RadiansToDegrees[theta_] := Degrees[theta / Pi 180] (** (defun degrees-to-radians (theta) ;; TYPE real -> radian ;; Convert angle theta from degrees to radians. ( * (degrees theta) pi 1/180)) **) DegreesToRadians[theta_] := Degrees[theta] Pi / 180 (** (defun sin-degrees (theta) ;; TYPE angle -> amplitude ;; Sine of theta (given in degrees). (sin (degrees-to-radians theta))) **) SinDegrees[theta_] := Sin[DegreesToRadians[theta]] (** (defun cosine-degrees (theta) ;; TYPE angle -> amplitude ;; Cosine of theta (given in degrees). (cos (degrees-to-radians theta))) **) CosineDegrees[theta_] := Cos[DegreesToRadians[theta]] (** (defun tangent-degrees (theta) ;; TYPE angle -> real ;; Tangent of theta (given in degrees). (tan (degrees-to-radians theta))) **) TangentDegrees[theta_] := Tan[DegreesToRadians[theta]] (** (defun arctan-degrees (x quad) ;; TYPE (real quadrant) -> angle ;; Arctangent of x in degrees in quadrant quad. (let* ((deg (radians-to-degrees (atan x)))) (if (or (= quad 1) (= quad 4)) deg (+ deg 180)))) **) ArcTanDegrees[x_, quad_] := Module[{deg}, deg = RadiansToDegrees[ArcTan[x]]; If[quad == 1 || quad == 4, deg, deg + 180] ] (** (defun arcsin-degrees (x) ;; TYPE amplitude -> angle ;; Arcsine of x in degrees. (radians-to-degrees (asin x))) **) ArcSinDegrees[x_] := RadiansToDegrees[ArcSin[x]] (** (defun arccos-degrees (x) ;; TYPE amplitude -> angle ;; Arccosine of x in degrees. (radians-to-degrees (acos x))) **) ArcCosDegrees[x_] := RadiansToDegrees[ArcCos[x]] (** (defun local-from-apparent (moment) ;; TYPE moment -> moment ;; Local time from sundial time. (- moment (equation-of-time moment))) **) LocalFromApparent[moment_] := moment - EquationOfTime[moment] (** (defun apparent-from-local (moment) ;; TYPE moment -> moment ;; Sundial time at local time. (+ moment (equation-of-time moment))) **) ApparentFromLocal[moment_] := moment + EquationOfTime[moment] (** (defun solar-moment (date latitude longitude rise-or-set) ;; TYPE (fixed-date angle angle real) -> moment ;; Local time (fraction of day) of sunrise/sunset at ;; latitude, longitude (in nonpolar regions) for fixed ;; date. rise-or-set is -0.25 for sunrise and +0.25 for ;; sunset. (let* ((approx ; Approximate time of event. (+ (day-number (gregorian-from-fixed date)) 0.5 rise-or-set (/ longitude -360.0d0))) (anomaly ; Anomaly of sun. (- ( * 0.9856d0 approx) 3.289d0)) (sun ; Longitude of sun. (degrees (+ anomaly ( * 1.916d0 (sin-degrees anomaly)) 282.634d0 ( * 0.020d0 (sin-degrees ( * 2 anomaly)))))) (right-ascension ; Right ascension of sun. (arctan-degrees ( * (cosine-degrees 23.441884d0) (tangent-degrees sun)) (1+ (quotient sun 90)))) ; Quadrant. (declination ; Declination of sun. (arcsin-degrees ( * (sin-degrees 23.441884d0) (sin-degrees sun)))) (local ( * (signum rise-or-set) (arccos-degrees (/ (- (cosine-degrees 90.833333d0) ( * (sin-degrees declination) (sin-degrees latitude))) (cosine-degrees declination) (cosine-degrees latitude)))))) (mod (- (/ (+ local right-ascension) 360) 0.27592d0 ( * 0.00273792d0 approx)) 1))) **) SolarMoment[date_Integer, latitude_, longitude_, riseOrSet_] := Module[{approx, anomaly, sun, rightAscension, declination, local}, approx = DayNumber[Gregorian[date]] + 0.5 + riseOrSet + (longitude / -360.0); anomaly = 0.9856 approx - 3.289; sun = Degrees[anomaly + 1.916 SinDegrees[anomaly] + 282.634 + 0.020 SinDegrees[2 anomaly]]; rightAscension = ArcTanDegrees[CosineDegrees[23.441884] TangentDegrees[sun], 1 + Quotient[sun, 90]]; declination = ArcSinDegrees[SinDegrees[23.441884] SinDegrees[sun]]; local = Sign[riseOrSet] ArcCosDegrees[ (CosineDegrees[90.833333] - SinDegrees[declination] SinDegrees[latitude]) / CosineDegrees[declination] / CosineDegrees[latitude]]; N[Mod[(local + rightAscension) / 360 - 0.27592 - 0.00273792 approx, 1]] ] (** (defun sunrise (date latitude longitude) ;; TYPE (fixed-date angle angle) -> moment ;; Local time (fraction of day) of sunrise at latitude, ;; longitude (in nonpolar regions) for fixed date. (solar-moment date latitude longitude -0.25d0)) **) Sunrise[date_Integer, latitude_, longitude_] := SolarMoment[date, latitude, longitude, -0.25] (** (defun sunset (date latitude longitude) ;; TYPE (fixed-date angle angle) -> moment ;; Local time (fraction of day) of sunset at latitude, ;; longitude (in nonpolar regions) for fixed date. (solar-moment date latitude longitude 0.25d0)) **) Sunset[date_Integer, latitude_, longitude_] := SolarMoment[date, latitude, longitude, 0.25] (** (defun universal-from-ephemeris (jd) ;; TYPE julian-day-number -> julian-day-number ;; Universal time from Ephemeris time. (- jd (ephemeris-correction (moment-from-jd jd)))) **) UniversalFromEphemeris[jd_] := jd - EphemerisCorrection[MomentFromJD[jd]] (** (defun ephemeris-from-universal (jd) ;; TYPE julian-day-number -> julian-day-number ;; Ephemeris time at Universal time. (+ jd (ephemeris-correction (moment-from-jd jd)))) **) EphemerisFromUniversal[jd_] := jd + EphemerisCorrection[MomentFromJD[jd]] (** (defconstant j2000 ;; TYPE julian-day-number ;; Julian day number (2451545) of Gregorian year 2000. (jd-from-moment (+ 0.5d0 (fixed-from-gregorian (gregorian-date january 1 2000))))) **) J2000[] = JDFromMoment[0.5 + ToFixed[Gregorian[January[], 1, 2000]]] (** (defun julian-centuries (moment) ;; TYPE moment -> moment ;; Julian centuries since j2000 at Universal time. (/ (- (ephemeris-from-universal moment) j2000) 36525d0)) **) JulianCenturies[moment_] := (EphemerisFromUniversal[moment] - J2000[]) / 36525 (** (defconstant mean-tropical-year ;; TYPE real 365.242199d0) **) MeanTropicalYear[] = 365.242199 (** (defconstant mean-synodic-month ;; TYPE real 29.530588853d0) **) MeanSynodicMonth[] = 29.530588853 (** (defun ephemeris-correction (moment) ;; TYPE moment -> fraction-of-day ;; Ephemeris Time minus Universal Time (in days) for ;; fixed time. Adapted from "Astronomical Algorithms" ;; by Jean Meeus, Willmann-Bell, Inc., 1991. (let* ((year (gregorian-year-from-fixed moment)) (theta (/ (gregorian-date-difference (gregorian-date january 1 1900) (gregorian-date july 1 year)) 36525d0)) (coeff-19th (list -0.00002d0 0.000297d0 0.025184d0 -0.181133d0 0.553040d0 -0.861938d0 0.677066d0 -0.212591d0)) (coeff-18th (list -0.000009d0 0.003844d0 0.083563d0 0.865736d0 4.867575d0 15.845535d0 31.332267d0 38.291999d0 28.316289d0 11.636204d0 2.043794d0))) (cond ((<= 1988 year 2019) (/ (- year 1933) 24d0 60d0 60d0)) ((<= 1900 year 1987) (poly theta coeff-19th)) ((<= 1800 year 1899) (poly theta coeff-18th)) ((<= 1620 year 1799) (/ (poly (- year 1600) (list 196.58333d0 -4.0675d0 0.0219167d0)) 24d0 60d0 60d0)) (t (let* ((x (+ 0.5d0 (gregorian-date-difference (gregorian-date january 1 1810) (gregorian-date january 1 year))))) (/ (- (/ ( * x x) 41048480d0) 15) 24d0 60d0 60d0)))))) **) EphemerisCorrection[moment_] := Module[{year, theta, coeff19th, coeff18th}, year = GregorianYearFromFixed[moment]; theta = DateDifference[Gregorian[January[], 1, 1900], Gregorian[July[], 1, year]] / 36525; coeff19th = {-0.00002, 0.000297, 0.025184, -0.181133, 0.553040, -0.861938, 0.677066, -0.212591}; coeff18th = {-0.000009, 0.003844, 0.083563, 0.865736, 4.867575, 15.845535, 31.332267, 38.291999, 28.316289, 11.636204, 2.043794}; Which[ 1988 <= year <= 2019, (year - 1933) / (24 60 60), 1900 <= year <= 1987, Poly[theta, coeff19th], 1800 <= year <= 1899, Poly[theta, coeff18th], 1620 <= year <= 1799, Poly[year - 1600, {196.58333, -4.0675, 0.0219167}] / (24 60 60), True, x = 0.5 + DateDifference[Gregorian[January[], 1, 1810], Gregorian[January[], 1, year]]; (x^2 / 41048480 - 15) / (24 60 60)] ] (** (defun equation-of-time (jd) ;; TYPE moment -> fraction-of-day ;; Equation of time (in days) for julian day number jd. ;; Adapted from "Astronomical Algorithms" by Jean Meeus, ;; Willmann-Bell, Inc., 1991. (let* ((c (/ (- jd j2000) 36525d0)) (longitude (poly c (list 280.46645d0 36000.76983d0 0.0003032d0))) (anomaly (poly c (list 357.52910d0 35999.05030d0 -0.0001559d0 -0.00000048d0))) (inclination (poly c (list 23.43929111d0 -0.013004167d0 -0.00000016389d0 0.0000005036d0))) (eccentricity (poly c (list 0.016708617d0 -0.000042037d0 -0.0000001236d0))) (y (expt (tangent-degrees (/ inclination 2)) 2))) (/ (+ ( * y (sin-degrees ( * 2 longitude))) ( * -2 eccentricity (sin-degrees anomaly)) ( * 4 eccentricity y (sin-degrees anomaly) (cosine-degrees ( * 2 longitude))) ( * -0.5 y y (sin-degrees ( * 4 longitude))) ( * -1.25 eccentricity eccentricity (sin-degrees ( * 2 anomaly)))) 2 pi))) **) EquationOfTime[jd_] := Module[{c, longitude, anomaly, inclination, eccentricity, y}, c = (jd - J2000[]) / 36525; longitude = Poly[c, {280.46645, 36000.76983, 0.0003032}]; anomaly = Poly[c, {357.52910, 35999.05030, -0.0001559, -0.00000048}]; inclination = Poly[c, {23.43929111, -0.013004167, -0.00000016389, 0.0000005036}]; eccentricity = Poly[c, {0.016708617, -0.000042037, -0.0000001236}]; y = TangentDegrees[inclination / 2]^2; N[(y SinDegrees[2 longitude] + -2 eccentricity SinDegrees[anomaly] + 4 eccentricity y SinDegrees[anomaly] CosineDegrees[2 longitude] + -0.5 y^2 SinDegrees[4 longitude] + -1.25 eccentricity^2 SinDegrees[2 anomaly]) / (2 Pi)] ] (** (defun solar-longitude (jd) ;; TYPE julian-day-number -> angle ;; Longitude of sun on astronomical (julian) day number jd. ;; Adapted from "Planetary Programs and Tables from -4000 ;; to +2800" by Pierre Bretagnon and Jean-Louis Simon, ;; Willmann-Bell, Inc., 1986. (let* ((c ; Ephemeris time in Julian centuries (julian-centuries jd)) (coefficients (list 403406 195207 119433 112392 3891 2819 1721 0 660 350 334 314 268 242 234 158 132 129 114 99 93 86 78 72 68 64 46 38 37 32 29 28 27 27 25 24 21 21 20 18 17 14 13 13 13 12 10 10 10 10)) (multipliers (list 0.01621043d0 628.30348067d0 628.30821524d0 628.29634302d0 1256.605691d0 1256.60984d0 628.324766d0 0.00813d0 1256.5931d0 575.3385d0 -0.33931d0 7771.37715d0 786.04191d0 0.05412d0 393.02098d0 -0.34861d0 1150.67698d0 157.74337d0 52.9667d0 588.4927d0 52.9611d0 -39.807d0 522.3769d0 550.7647d0 2.6108d0 157.7385d0 1884.9103d0 -77.5655d0 2.6489d0 1179.0627d0 550.7575d0 -79.6139d0 1884.8981d0 21.3219d0 1097.7103d0 548.6856d0 254.4393d0 -557.3143d0 606.9774d0 21.3279d0 1097.7163d0 -77.5282d0 1884.9191d0 2.0781d0 294.2463d0 -0.0799d0 469.4114d0 -0.6829d0 214.6325d0 1572.084d0)) (addends (list 4.721964d0 5.937458d0 1.115589d0 5.781616d0 5.5474d0 1.512d0 4.1897d0 1.163d0 5.415d0 4.315d0 4.553d0 5.198d0 5.989d0 2.911d0 1.423d0 0.061d0 2.317d0 3.193d0 2.828d0 0.52d0 4.65d0 4.35d0 2.75d0 4.5d0 3.23d0 1.22d0 0.14d0 3.44d0 4.37d0 1.14d0 2.84d0 5.96d0 5.09d0 1.72d0 2.56d0 1.92d0 0.09d0 5.98d0 4.03d0 4.47d0 0.79d0 4.24d0 2.01d0 2.65d0 4.98d0 0.93d0 2.21d0 3.59d0 1.5d0 2.55d0)) (longitude (+ 4.9353929d0 ( * 628.33196168d0 c) ( * 0.0000001d0 (sigma ((x coefficients) (y addends) (z multipliers)) ( * x (sin (+ y ( * z c))))))))) (radians-to-degrees (+ longitude (aberration c) (nutation c))))) **) SolarLongitude[jd_] := Module[{c, coefficients, multipliers, addends, longitude, x, y, z}, c = JulianCenturies[jd]; coefficients = {403406, 195207, 119433, 112392, 3891, 2819, 1721, 0, 660, 350, 334, 314, 268, 242, 234, 158, 132, 129, 114, 99, 93, 86, 78, 72, 68, 64, 46, 38, 37, 32, 29, 28, 27, 27, 25, 24, 21, 21, 20, 18, 17, 14, 13, 13, 13, 12, 10, 10, 10, 10}; multipliers = {0.01621043, 628.30348067, 628.30821524, 628.29634302, 1256.605691, 1256.60984, 628.324766, 0.00813, 1256.5931, 575.3385, -0.33931, 7771.37715, 786.04191, 0.05412, 393.02098, -0.34861, 1150.67698, 157.74337, 52.9667, 588.4927, 52.9611, -39.807, 522.3769, 550.7647, 2.6108, 157.7385, 1884.9103, -77.5655, 2.6489, 1179.0627, 550.7575, -79.6139, 1884.8981, 21.3219, 1097.7103, 548.6856, 254.4393, -557.3143, 606.9774, 21.3279, 1097.7163, -77.5282, 1884.9191, 2.0781, 294.2463, -0.0799, 469.4114, -0.6829, 214.6325, 1572.084}; addends = {4.721964, 5.937458, 1.115589, 5.781616, 5.5474, 1.512, 4.1897, 1.163, 5.415, 4.315, 4.553, 5.198, 5.989, 2.911, 1.423, 0.061, 2.317, 3.193, 2.828, 0.52, 4.65, 4.35, 2.75, 4.5, 3.23, 1.22, 0.14, 3.44, 4.37, 1.14, 2.84, 5.96, 5.09, 1.72, 2.56, 1.92, 0.09, 5.98, 4.03, 4.47, 0.79, 4.24, 2.01, 2.65, 4.98, 0.93, 2.21, 3.59, 1.5, 2.55}; longitude = 4.9353929 + 628.33196168 c + 0.0000001 Sigma[{{x, coefficients}, {y, addends}, {z, multipliers}}, x Sin[z c + y]]; N[RadiansToDegrees[longitude + Aberration[c] + Nutation[c]]] ] (** (defun nutation (c) ;; TYPE julian-centuries -> radian ;; Longitudinal nutation in radians at c Julian centuries. (let* ((A (poly c (list 124.90d0 -1934.134d0 0.002063d0))) (B (poly c (list 201.11d0 72001.5377d0 0.00057d0)))) (+ ( * -.0000834d0 (sin-degrees A)) ( * -.0000064d0 (sin-degrees B))))) **) Nutation[c_] := Module[{a, b}, a = Poly[c, {124.90, -1934.134, 0.002063}]; b = Poly[c, {201.11, 72001.5377, 0.00057}]; -.0000834 SinDegrees[a] + -.0000064 SinDegrees[b] ] (** (defun aberration (c) ;; TYPE julian-centuries -> radian ;; Aberration in radians at c Julian centuries. (- ( * 0.0000017d0 (cosine-degrees (+ 177.63d0 ( * 35999.01848d0 c)))) 0.0000973d0)) **) Aberration[c_] := 0.0000017 CosineDegrees[177.63 + 35999.01848 c] - 0.0000973; (** (defun date-next-solar-longitude (jd l) ;; TYPE (julian-day-number angle) -> julian-day-number ;; Julian day number of the first date at or after julian ;; day number jd (in Greenwich) when the solar longitude ;; will be a multiple of l degrees; l must be a proper ;; divisor of 360. (let* ((next (double-float (degrees ( * l (ceiling (/ (solar-longitude jd) l))))))) (binary-search start jd end (+ jd ( * (/ l 360) 400d0)) x (if (= next 0); Discontinuity at next=0 ;; Then test for drop in longitude (>= l (solar-longitude x)) ;; Else test if we are past the desired ;; longitude