def approx_moment_of_depression(self, tee, alpha, early): """Return the moment in local time near tee when depression angle of sun is alpha (negative if above horizon) at location; early is true when MORNING event is sought and false for EVENING. Raise VlueError if depression angle is not reached.""" ttry = self.sine_offset(tee, alpha) date = Clock.fixed_from_moment(tee) if alpha >= 0: if early: alt = date else: alt = date + 1 else: alt = date + Clock.days_from_hours(12) if abs(ttry) > 1: value = self.sine_offset(alt, alpha) else: value = ttry if abs(value) <= 1: temp = -1 if early else 1 temp *= mod(Clock.days_from_hours(12) + arcsin_degrees(value) / 360, 1) - Clock.days_from_hours(6) temp += date + Clock.days_from_hours(12) return self.local_from_apparent(temp) else: raise ValueError("Depression angle not reached")
def location(cls, tee): """Return location of Beijing; time zone varies with time, tee.""" year = GregorianDate.to_year(ifloor(tee)) if (year < 1929): return Location(angle(39, 55, 0), angle(116, 25, 0), 43.5, Clock.days_from_hours(1397/180)) else: return Location(angle(39, 55, 0), angle(116, 25, 0), 43.5, Clock.days_from_hours(8))
def japanese_location(tee): """Return the location for Japanese calendar; varies with moment, tee.""" year = GregorianDate.to_year(ifloor(tee)) if (year < 1888): # Tokyo (139 deg 46 min east) local time loc = Location(mpf(35.7), angle(139, 46, 0), 24, Clock.days_from_hours(9 + 143/450)) else: # Longitude 135 time zone loc = Location(35, 135, 0, Clock.days_from_hours(9)) return loc
def molad(cls, month, year): """Return moment of mean conjunction of month in Hebrew year.""" y = year + 1 if month < HebrewMonth.TISHRI else year months_elapsed = month - HebrewMonth.TISHRI + quotient(235 * y - 234, 19) return ( cls.EPOCH - Fraction(876, 25920) + months_elapsed * (29 + Clock.days_from_hours(12) + Fraction(793, 25920)) )
def from_fixed(cls, date): """Return Old Hindu solar date equivalent to fixed date date.""" sun = cls.hindu_day_count(date) + Clock.days_from_hours(6) year = quotient(sun, cls.ARYA_SOLAR_YEAR) month = mod(quotient(sun, cls.ARYA_SOLAR_MONTH), 12) + 1 day = ifloor(mod(sun, cls.ARYA_SOLAR_MONTH)) + 1 return OldHinduSolarDate(year, month, day)
def sunset(cls, date): """Return sunset at HINDU_LOCATION on date, date.""" return (date + Clock.days_from_hours(18) + ((cls.UJJAIN.longitude - cls.LOCATION.longitude) / 360) - cls.equation_of_time(date) + (((1577917828/1582237828) / 360) * (- cls.ascensional_difference(date, cls.LOCATION) + (3/4 * cls.solar_sidereal_difference(date)))))
def sunrise(cls, date): """Return the sunrise at hindu_location on date, date.""" return (date + Clock.days_from_hours(6) + ((cls.UJJAIN.longitude - cls.LOCATION.longitude) / 360) - cls.equation_of_time(date) + ((1577917828/1582237828 / 360) * (cls.ascensional_difference(date, cls.LOCATION) + (1/4 * cls.solar_sidereal_difference(date)))))
def vietnamese_location(tee): """Return the location for Vietnamese calendar is Hanoi; varies with moment, tee. Time zone has changed over the years.""" if (tee < GregorianDate.new_year(1968)): z = 8 else: z =7 return Location(angle(21, 2, 0), angle(105, 51, 0), 12, Clock.days_from_hours(z))
def sundial_time(cls, tee): """Return Hindu local time of temporal moment, tee.""" date = Clock.fixed_from_moment(tee) time = mod(tee, 1) q = ifloor(4 * time) if q == 0: a = cls.sunset(date - 1) b = cls.sunrise(date) t = Clock.days_from_hours(-6) elif q == 3: a = cls.sunset(date) b = cls.sunrise(date + 1) t = Clock.days_from_hours(18) else: a = cls.sunrise(date) b = cls.sunset(date) t = Clock.days_from_hours(6) return a + (2 * (b - a) * (time - t))
def to_fixed(self): """Return the fixed date of this Hindu lunar date.""" approx = OldHindu.EPOCH + (self.SIDEREAL_YEAR * (self.year + self.LUNAR_ERA + ((self.month - 1) / 12))) s = ifloor(approx - ((1/360) * self.SIDEREAL_YEAR * mod(self.hindu_solar_longitude(approx) - ((self.month - 1) * 30) + 180, 360) - 180)) k = self.lunar_day_from_moment(s + Clock.days_from_hours(6)) if (3 < k < 27): temp = k else: mid = self.lunar_from_fixed(s - 15) if ((mid.month != self.month) or (mid.leap_month and not self.leap_month)): temp = mod(k + 15, 30) - 15 else: temp = mod(k - 15, 30) + 15 est = s + self.day - temp tau = est - mod(self.lunar_day_from_moment(est + Clock.days_from_hours(6)) - self.day + 15, 30) + 15 date = next_int(tau - 1, lambda d: self.lunar_day_from_moment(self.sunrise(d)) in [self.day, amod(self.day + 1, 30)]) return date + 1 if self.leap_day else date
def moment_of_depression(self, approx, alpha, early): """Return the moment in local time near approx when depression angle of sun is alpha (negative if above horizon) at location; early is true when MORNING event is sought, and false for EVENING.""" tee = self.approx_moment_of_depression(approx, alpha, early) if abs(approx - tee) < Clock.days_from_seconds(30): return tee else: return self.moment_of_depression(tee, alpha, early)
def from_fixed(cls, fixed_date): """Return Old Hindu lunar date equivalent to fixed date 'fixed_date'.""" sun = cls.hindu_day_count(fixed_date) + Clock.days_from_hours(6) new_moon = sun - mod(sun, cls.ARYA_LUNAR_MONTH) leap = cls.ARYA_SOLAR_MONTH - cls.ARYA_LUNAR_MONTH >= mod(new_moon, cls.ARYA_SOLAR_MONTH) and mod(new_moon, cls.ARYA_SOLAR_MONTH) > 0 month = mod(iceiling(new_moon / cls.ARYA_SOLAR_MONTH), 12) + 1 day = mod(quotient(sun, cls.ARYA_LUNAR_DAY), 30) + 1 year = iceiling((new_moon + cls.ARYA_SOLAR_MONTH) / cls.ARYA_SOLAR_YEAR) - 1 return OldHinduLunarDate(year, month, leap, day)
def hindu_tithi_occur(l_month, tithi, tee, l_year): """Return the fixed date of occurrence of Hindu lunar tithi prior to sundial time, tee, in Hindu lunar month, l_month, and year, l_year.""" approx = hindu_date_occur(l_month, ifloor(tithi), l_year) lunar = HinduLunarDate.day_at_or_after(tithi, approx - 2) ttry = Clock.fixed_from_moment(lunar) tee_h = HinduLunarDate.UJJAIN.standard_from_sundial(ttry + tee) if lunar <= tee_h or HinduLunarDate.lunar_phase(HinduLunarDate.UJJAIN.standard_from_sundial(ttry + 1 + tee)) > 12 * tithi: return ttry else: return ttry + 1
def moonrise(self, date): """Return the standard time of moonrise on fixed, date, and location, location.""" t = self.universal_from_standard(date) waning = (Lunar.lunar_phase(t) > 180) alt = self.observed_lunar_altitude(t) offset = alt / 360 if waning and (offset > 0): approx = t + 1 - offset elif waning: approx = t - offset else: approx = t + (1 / 2) + offset rise = binary_search(approx - Clock.days_from_hours(3), approx + Clock.days_from_hours(3), lambda u, l: ((u - l) < Clock.days_from_hours(1/60)), lambda x: self.observed_lunar_altitude(x) > 0) if rise < (t + 1): return self.standard_from_universal(rise) raise ValueError()
def to_fixed(self): """Return the fixed date corresponding to Hindu lunar date, l_date.""" approx = (OldHindu.EPOCH + self.MEAN_SIDEREAL_YEAR * (self.year + self.LUNAR_ERA + ((self.month - 1) / 12))) s = ifloor(approx - 1/360 * self.MEAN_SIDEREAL_YEAR * (mod(sidereal_solar_longitude(approx) - (self.month - 1) * 30 + 180, 360) - 180)) k = self.day_from_moment(s + Clock.days_from_hours(6)) if (3 < k < 27): temp = k else: mid = self.from_fixed(s - 15) if ((mid.month != self.month) or (mid.leap_month and not self.leap_month)): temp = mod(k + 15, 30) - 15 else: temp = mod(k - 15, 30) + 15 est = s + self.day - temp tau = est - mod(self.day_from_moment(est + Clock.days_from_hours(6)) - self.day + 15, 30) + 15 date = next_int(tau - 1, lambda d: (self.day_from_moment(self.alt_sunrise(d)) in [self.day, amod(self.day + 1, 30)])) return (date + 1) if self.leap_day else date
def korean_location(tee): """Return the location for Korean calendar; varies with moment, tee.""" # Seoul city hall at a varying time zone. if (tee < GregorianDate(1908, MonthOfYear.April, 1).to_fixed()): #local mean time for longitude 126 deg 58 min z = 3809/450 elif (tee < GregorianDate(1912, MonthOfYear.January, 1).to_fixed()): z = 8.5 elif (tee < GregorianDate(1954, MonthOfYear.March, 21).to_fixed()): z = 9 elif (tee < GregorianDate(1961, MonthOfYear.August, 10).to_fixed()): z = 8.5 else: z = 9 return Location(angle(37, 34, 0), angle(126, 58, 0), 0, Clock.days_from_hours(z))
def equation_of_time(cls, tee): """Return the equation of time (as fraction of day) for moment, tee. Adapted from "Astronomical Algorithms" by Jean Meeus, Willmann_Bell, Inc., 1991.""" c = cls.julian_centuries(tee) lamb = poly(c, [mpf(280.46645), mpf(36000.76983), mpf(0.0003032)]) anomaly = poly(c, [mpf(357.52910), mpf(35999.05030), mpf(-0.0001559), mpf(-0.00000048)]) eccentricity = poly(c, [mpf(0.016708617), mpf(-0.000042037), mpf(-0.0000001236)]) varepsilon = cls.obliquity(tee) y = pow(tan_degrees(varepsilon / 2), 2) equation = ((1/2 / pi) * (y * sin_degrees(2 * lamb) + -2 * eccentricity * sin_degrees(anomaly) + (4 * eccentricity * y * sin_degrees(anomaly) * cos_degrees(2 * lamb)) + -0.5 * y * y * sin_degrees(4 * lamb) + -1.25 * eccentricity * eccentricity * sin_degrees(2 * anomaly))) return signum(equation) * min(abs(equation), Clock.days_from_hours(mpf(12)))
def standard_from_sundial(self, tee): """Return standard time of temporal moment, tee, at location, location.""" date = Clock.fixed_from_moment(tee) hour = 24 * mod(tee, 1) if 6 <= hour <= 18: h = self.daytime_temporal_hour(date) elif (hour < 6): h = self.nighttime_temporal_hour(date - 1) else: h = self.nighttime_temporal_hour(date) # return if 6 <= hour <= 18: return self.sunrise(date) + ((hour - 6) * h) elif hour < 6: return self.sunset(date - 1) + ((hour + 6) * h) else: return self.sunset(date) + ((hour - 18) * h)
def ephemeris_correction(cls, tee): """Return Dynamical Time minus Universal Time (in days) for moment, tee. Adapted from "Astronomical Algorithms" by Jean Meeus, Willmann_Bell, Inc., 1991.""" year = GregorianDate.to_year(ifloor(tee)) c = GregorianDate.date_difference(GregorianDate(1900, JulianMonth.January, 1), GregorianDate(year, JulianMonth.July, 1)) / mpf(36525) if 1988 <= year <= 2019: return 1/86400 * (year - 1933) elif 1900 <= year <= 1987: return poly(c, [mpf(-0.00002), mpf(0.000297), mpf(0.025184), mpf(-0.181133), mpf(0.553040), mpf(-0.861938), mpf(0.677066), mpf(-0.212591)]) elif 1800 <= year <= 1899: return poly(c, [mpf(-0.000009), mpf(0.003844), mpf(0.083563), mpf(0.865736), mpf(4.867575), mpf(15.845535), mpf(31.332267), mpf(38.291999), mpf(28.316289), mpf(11.636204), mpf(2.043794)]) elif 1700 <= year <= 1799: return 1/86400 * poly(year - 1700, [8.118780842, -0.005092142, 0.003336121, -0.0000266484]) elif 1620 <= year <= 1699: return 1/86400 * poly(year - 1600, [mpf(196.58333), mpf(-4.0675), mpf(0.0219167)]) else: x = Clock.days_from_hours(mpf(12)) + GregorianDate.date_difference(GregorianDate(1810, JulianMonth.January, 1), GregorianDate(year, JulianMonth.January, 1)) return 1/86400 * (((x * x) / mpf(41048480)) - 15)
elif month == HebrewMonth.KISLEV and day < 30: extra = [DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday] elif month == HebrewMonth.KISLEV and day == 30: extra = [DayOfWeek.Monday] elif month in [HebrewMonth.TEVET, HebrewMonth.SHEVAT]: extra = [DayOfWeek.Sunday, DayOfWeek.Monday] elif month == HebrewMonth.ADAR and day < 30: extra = [DayOfWeek.Sunday, DayOfWeek.Monday] else: extra = [DayOfWeek.Sunday] basic.extend(extra) return map(lambda x: DayOfWeek.from_fixed(x + n), basic) JAFFA = Location(angle(32, 1, 60), angle(34, 45, 0), 0, Clock.days_from_hours(2)) class HebrewObservationalDate(YearMonthDay): def __init__(self, year, month, day): YearMonthDay.__init__(self, year, month, day) def to_fixed(self): """Return fixed date equivalent to Observational Hebrew date.""" year1 = self.year - 1 if self.month >= HebrewMonth.TISHRI else self.year start = HebrewDate(year1, HebrewMonth.NISAN, 1).to_fixed() g_year = GregorianDate.to_year(start + 60) new_year = self.new_year(g_year) midmonth = new_year + iround(29.5 * (self.month - 1)) + 15 return JAFFA.phasis_on_or_before(midmonth) + self.day - 1
def to_fixed(self): """Return fixed date corresponding to Old Hindu solar date s_date.""" return iceiling(self.EPOCH + self.year * self.ARYA_SOLAR_YEAR + (self.month - 1) * self.ARYA_SOLAR_MONTH + self.day + Clock.days_from_hours(-30))
def midday(self, date): """Return standard time on fixed date, date, of midday at location, location.""" return self.standard_from_local(self.local_from_apparent(date + Clock.days_from_hours(mpf(12))))
def to_fixed(self): """Return fixed date corresponding to Old Hindu lunar date l_date.""" mina = ((12 * self.year) - 1) * self.ARYA_SOLAR_MONTH lunar_new_year = self.ARYA_LUNAR_MONTH * (quotient(mina, self.ARYA_LUNAR_MONTH) + 1) if not self.leap and iceiling((lunar_new_year - mina) / (self.ARYA_SOLAR_MONTH - self.ARYA_LUNAR_MONTH)) <= self.month: temp = self.month else: temp = self.month - 1 temp = self.EPOCH + lunar_new_year + (self.ARYA_LUNAR_MONTH * temp) + ((self.day - 1) * self.ARYA_LUNAR_DAY) + Clock.days_from_hours(-6) return iceiling(temp)
def dusk(self, date, alpha): """Return standard time in evening on fixed date 'date' at location 'location' when depression angle of sun is alpha.""" result = self.moment_of_depression(date + Clock.days_from_hours(18), alpha, self.EVENING) return self.standard_from_local(result)
def dawn(self, date, alpha): """Return standard time in morning on fixed date date at location location when depression angle of sun is alpha.""" result = self.moment_of_depression(date + Clock.days_from_hours(6), alpha, self.MORNING) return self.standard_from_local(result)
def shiva(gregorian_year): """Return the list of fixed date(s) of Night of Shiva in Gregorian year, 'gregorian_year'.""" return hindu_lunar_event(11, 29, Clock.days_from_hours(24), gregorian_year)
ignoring parallax and refraction. Adapted from 'Astronomical Algorithms' by Jean Meeus, Willmann_Bell, Inc., 1998.""" lamb = Lunar.lunar_longitude(tee) beta = Lunar.lunar_latitude(tee) alpha = Astro.right_ascension(tee, beta, lamb) delta = Astro.declination(tee, beta, lamb) theta0 = Astro.sidereal_from_moment(tee) cap_H = mod(theta0 + self.longitude - alpha, 360) altitude = arcsin_degrees( (sin_degrees(self.latitude) * sin_degrees(delta)) + (cos_degrees(self.latitude) * cos_degrees(delta) * cos_degrees(cap_H))) return mod(altitude + 180, 360) - 180 def visible_crescent(self, date): """Return S. K. Shaukat's criterion for likely visibility of crescent moon on eve of date 'date', at location 'location'.""" tee = self.universal_from_standard(self.dusk(date - 1, mpf(4.5))) phase = Lunar.lunar_phase(tee) altitude = self.lunar_altitude(tee) arc_of_light = arccos_degrees(cos_degrees(Lunar.lunar_latitude(tee)) * cos_degrees(phase)) return ((Lunar.NEW < phase < Lunar.FIRST_QUARTER) and (mpf(10.6) <= arc_of_light <= 90) and (altitude > mpf(4.1))) MECCA = Location(angle(21, 25, 24), angle(39, 49, 24), 298, Clock.days_from_hours(3)) JERUSALEM = Location(31.8, 35.2, 800, Clock.days_from_hours(2)) BRUXELLES = Location(angle(4, 21, 17), angle(50, 50, 47), 800, Clock.days_from_hours(1)) URBANA = Location(40.1, -88.2, 225, Clock.days_from_hours(-6)) GREENWHICH = Location(51.4777815, 0, 46.9, Clock.days_from_hours(0))
def rama(gregorian_year): """Return the list of fixed date(s) of Rama's Birthday in Gregorian year, 'gregorian_year'.""" return hindu_lunar_event(1, 9, Clock.days_from_hours(12), gregorian_year)