mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Add MOONPHASE(date) function
This commit is contained in:
parent
0006e0604b
commit
3c610b365b
@ -1,3 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
import calendar
|
import calendar
|
||||||
import datetime
|
import datetime
|
||||||
import dateutil.parser
|
import dateutil.parser
|
||||||
@ -780,3 +781,51 @@ def YEARFRAC(start_date, end_date, basis=0):
|
|||||||
def _one_year_frac(start_date, end_date):
|
def _one_year_frac(start_date, end_date):
|
||||||
year_length = 366.0 if calendar.isleap(start_date.year) else 365.0
|
year_length = 366.0 if calendar.isleap(start_date.year) else 365.0
|
||||||
return (end_date - start_date).days / year_length
|
return (end_date - start_date).days / year_length
|
||||||
|
|
||||||
|
|
||||||
|
# Constants for moon phase calculations.
|
||||||
|
_new_moon_date = datetime.date(1900, 1, 1) # Known new moon.
|
||||||
|
_synodic_month = 29.530588853 # Length of synodic month, in days.
|
||||||
|
|
||||||
|
def MOONPHASE(date, output="emoji"):
|
||||||
|
"""
|
||||||
|
Returns the phase of the moon on the given date. The output defaults to a moon-phase emoji.
|
||||||
|
|
||||||
|
- With `output="days"`, the output is the age of the moon in days (new moon being 0).
|
||||||
|
- With `output="fraction"`, the output is the fraction of the lunar month since new moon.
|
||||||
|
|
||||||
|
The calculation isn't astronomically precise, but good enough for wolves and sailors.
|
||||||
|
|
||||||
|
Do NOT! use `output="lunacy"`.
|
||||||
|
|
||||||
|
>>> MOONPHASE(datetime.date(1900, 1, 1), "days")
|
||||||
|
0.0
|
||||||
|
>>> MOONPHASE(datetime.date(1900, 1, 1), "fraction")
|
||||||
|
0.0
|
||||||
|
>>> MOONPHASE(datetime.datetime(1900, 1, 1))
|
||||||
|
'🌑'
|
||||||
|
>>> MOONPHASE(datetime.date(1900, 1, 15))
|
||||||
|
'🌕'
|
||||||
|
>>> MOONPHASE(datetime.date(1900, 1, 30))
|
||||||
|
'🌑'
|
||||||
|
>>> [MOONPHASE(DATEADD(datetime.date(2023, 4, 1), days=4*n)) for n in range(8)]
|
||||||
|
['🌔', '🌕', '🌖', '🌗', '🌘', '🌑', '🌒', '🌓']
|
||||||
|
>>> [round(MOONPHASE(DATEADD(datetime.date(2023, 4, 1), days=4*n), "days"), 1) for n in range(8)]
|
||||||
|
[10.4, 14.4, 18.4, 22.4, 26.4, 0.9, 4.9, 8.9]
|
||||||
|
"""
|
||||||
|
days = (_make_datetime(date).date() - _new_moon_date).total_seconds() / 86400.
|
||||||
|
age = days % _synodic_month
|
||||||
|
phase = age / _synodic_month
|
||||||
|
if output == "fraction":
|
||||||
|
return phase
|
||||||
|
elif output == "days":
|
||||||
|
return age
|
||||||
|
else:
|
||||||
|
# DRAW THE MOON'S PHASES WITH EMOJI. ALL MOON PHASES ARE BEAUTIFUL, EVEN (near) INSTANT
|
||||||
|
# ONES LIKE NEW, QUARTER, AND FULL (my fave, AWOOOO!) TO BE FAIR TO ALL PHASES, DIVIDE UP
|
||||||
|
# EACH QUARTER INTO 10% FOR THE SHORT PHASES, 15% FOR THE LONG ONES.
|
||||||
|
quarter, frac = divmod((phase + 0.05) % 1, 0.25)
|
||||||
|
index = int(quarter) * 2 + int(frac > 0.1)
|
||||||
|
if output == "lunacy":
|
||||||
|
return "🐺" if index == 4 else "🕺"
|
||||||
|
return ["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"][index]
|
||||||
|
Loading…
Reference in New Issue
Block a user