Die Kraft der Gravitation des Mondes auf die Erde ist so groß, dass sie alle Ozeane bewegt und Ebbe und Flut hervorruft. Bedenkt man außerdem, dass der Mensch zu zwei Dritteln aus Wasser besteht, und dass dies ebenso oder in noch höherem Ausmaß für alle Tiere und Pflanzen gilt, ist es nicht verwunderlich, dass es seit altersher Überlieferungen gibt, wie der Mond Gesundheit, Stimmungen, aber auch Viehzucht und Ernte beeinflusst.
Was von diesen empirischen Beobachtungen richtig ist, und was nur Folklore, das wollen wir an dieser Stelle nicht beurteilen. Aber falls Sie z.B. eine Parasitenkur nach dem Vollmond ausrichten, in Ihrem Garten günstige Saattermine finden, oder, für die Damen, den besten Zeitpunkt fürs Haareschneiden ermitteln wollen, haben wir heute eine passende Software für Sie.
Unser Python-Script moon-calendar.py ermittelt die Mondphasen, und als kleiner Clou kann es außerdem die Entfernung des Mondes zur Erde berechnen. Dadurch kann es auch die sog. „Supermonde“ kennzeichnen, das sind Vollmonde, bei denen der Mond näher als 360.000 KM zur Erde ist.
Der Effekt eines Supermondes ist umstritten, manche sagen, er würde Springfluten hervorrufen und Erdbeben begünstigen. Astronomisch betrachtet, ist das allerdings relativ unwahrscheinlich. Die mittlere Entfernung des Mondes beträgt 385.000 KM, der Effekt der Gravitation verstärkt sich wegen der etwas geringeren Entfernung bei einem Supermond nur wenig. Sei’s drum, es geht immer wieder gerne durch die Presse, also haben wir es als netten Effekt mit eingebaut.
Wir haben in den Berechnungen die Einflüsse der Gravitation der anderen Planeten außer Acht gelassen. Die Zeitpunkte der Mondphasen werden in so überwältigendem Maß von der Gravitation von Sonne und Erde bestimmt, dass man die Effekte der anderen Himmelskörper ignorieren kann. Da wir uns außerdem die Umrechnung in UT gespart haben (UT = Universal Time, ET = Ephemeris Time – die UT differiert von der ET, weil sich die Rotation der Erde aus unbekanntem Grund und in unvorhersagbaren Größen und Intervallen verlangsamt und dadurch gegenüber der, sozusagen, Zeitrechnung unseres Sonnensystems differiert; und das kann nur empirisch gemessen werden und ergibt deshalb einen riesigen Datensatz); durch ein paar Verkürzungsschritte bei der Anwendung der astronomischen Algorithmen von Jean Meeus erzielen wir eine Genauigkeit von ca. +/- 2 Minuten für den exakten Zeitpunkt einer Mondphase. Dies betrachten wir jedoch als völlig ausreichend, um z.B. gesundheitliche oder landwirtschaftliche Aktivitäten zu planen.
Unsere Software berechnet alle 4 Phasen des Mondes, also Neumond, zunehmendes Viertel, Vollmond, abnehmendes Viertel. Im Default gibt sie jedoch nur Neumond und Vollmond aus, mit der Option -a erhalten Sie alle Phasen. Sie können sich das Ergebnis der Berechnung entweder auf die Konsole ausgeben lassen, oder als TXT, CSV oder ICS erzeugen. Die Möglichkeit, eine ICS Kalenderdatei zu generieren, ist besonders interessant, das weitverbreitete ICS-Format lässt sich in viele Kalenderanwendungen importieren, und unser Programm unterstützt auch die Einrichtung von Erinnnerungen für die Mondphasenzeitpunkte, damit man sich vorbereiten kann.
Falls Sie das Programm nicht bei sich installieren möchten, finden Sie in unserem Downloadbereich übrigens auch Dateien mit den Mondphasen für die nächsten 10 Jahre (in den unterstützten Formaten, also TXT, CSV, ICS). Die vollständige Berechnung mit allen Phasen können Sie hier herunterladen, die verkürzte Version mit nur Neu- und Vollmond finden Sie hier.
Die Software dazu, falls Sie z.B. andere Zeiträume konfigurieren, oder Erinnerungszeitpunkte festlegen möchten (die ICS-Daten im Downloadbereich sind ohne Erinnerungen erstellt worden), können Sie entweder als ZIP herunterladen, oder Sie kopieren sie aus dem nachfolgenden Fenster heraus. Python3 wird benötigt, um die Software auszuführen – in Linux-Systemen i.Allg. vorinstalliert, unter Windows können Sie es problemlos hinzufügen.
#!/usr/bin/env python3 ################################################################################ # Erfordert diese beiden Nicht-Standard-Bibliotheken: # pip install icalendar # pip install pytz ################################################################################ # Berechnet die Mondphasen und die Entfernung des Mondes zum Phasenzeitpunkt # Genauigkeit der Mondphasen +/- 2 Minuten # Markiert dabei den sog. "Supermond" == Vollmond mit Entfernung < 360.000 KM # Ausgabe möglich auf stdout, als CSV (im deutschen Format, delimiter == ';'), # als Tab-getrennte Textdatei, und als ICS Kalenderdatei # # Astronomische Formeln nach "Astronomical Algorithms" von Jean Meeuss (1991) # Teile des Codes (CLI, Export nach ICS) mit Unterstützung von ChatGPT 4o ################################################################################ # usage: moon-calendar.py [-h] [-b BEGINN] [-e ENDE] [-a] [-o OUTPUT] # [-r REMINDER] [-z TIMEZONE] # # Berechne Mondphasen; Ausgabe in stdout, CSV, TXT oder ICS # # options: # -h, --help show this help message and exit # -b BEGINN, --beginn BEGINN # Startdatum für Mondphasen (Format: YYYY-MM-DD). # Default: [Heute] # -e ENDE, --ende ENDE Enddatum für Mondphasen (Format: YYYY-MM-DD). Default: # [Heute + 10 Jahre] # -a, --alle-phasen Alle Mondphasen einbeziehen (inklusive Halbmonde). # Standard: nur Neumond und Vollmond. # -o OUTPUT, --output OUTPUT # Output file name (default: stdout) # -r REMINDER, --reminder REMINDER # Anzahl der Tage vorher für eine Erinnerung. Default: 0 # (keine Erinnerung). # -z TIMEZONE, --timezone TIMEZONE # Zeitzone für die Termine, Default 'Europe/Berlin'. Für # gültige Zeitzonen siehe: https://en.wikipedia.org/wiki # /List_of_tz_database_time_zones ################################################################################ from datetime import datetime, timedelta from icalendar import Calendar, Event, Alarm import math, argparse, sys, pytz, csv TIMEZONE = 'Europe/Berlin' def decimalYear(date): year_start = datetime(date.year, 1, 1) next_year_start = datetime(date.year + 1, 1, 1) days_in_year = (next_year_start - year_start).days days_passed = (date - year_start).days return date.year + days_passed / days_in_year def SIN(g): return math.sin(math.radians(g)) def COS(g): return math.cos(math.radians(g)) def frac(n): return n - int(n) def date2jd(cd): Y = cd.year M = cd.month D = cd.day + (cd.hour + cd.minute / 60 + cd.second / 3600) / 24 if M <= 2: Y = Y - 1 M = M + 12 A = int(Y / 100) if cd >= datetime(1582, 10, 15, 0, 0, 0): # Gregorianischer Kalender B = 2 - A + int(A / 4) else: # Julianischer Kalender B = 0 return int(365.25 * (Y + 4716)) + int(30.6001 * (M + 1)) + D + B - 1524.5 # Setzt eine gültige Zeitzonenangabe in der globalen Variable TIMEZONE voraus def jd2date(jd): JD = jd + 0.5 Z = int(JD) F = frac(JD) if Z < 2299161: A = Z else: alpha = int((Z - 1867216.25) / 36524.24) A = Z + 1 + alpha - int(alpha / 4) B = A + 1524 C = int((B - 122.1) / 365.25) D = int(365.25 * C) E = int((B - D) / 30.6001) result = {} fullday = B - D - int(30.6001 * E) + F result['day'] = int(fullday) result['hour'] = int(frac(fullday) * 24) result['minute'] = int(frac((frac(fullday) * 24)) * 60) result['second'] = int(frac(frac(frac(fullday) * 24) * 60) * 60) if E < 14: result['month'] = E - 1 else: result['month'] = E - 13 if result['month'] > 2: result['year'] = C - 4716 else: result['year'] = C - 4715 return pytz.utc.localize(datetime(result['year'], result['month'], result['day'], \ result['hour'], result['minute'], result['second'])).astimezone(pytz.timezone(TIMEZONE)) def previousNewMoon_k(cd): return int((decimalYear(cd) - 2000) * 12.3685) def julianCenturiesSince2000(jd): return (jd - 2451545) / 36525 def earthEccentricity(jd): T = julianCenturiesSince2000(jd) return 1 - 0.002516 * T - 0.0000074 * T**2 def roundJD(jd): # rounds to minutes m = frac(jd) * 24 * 60 m = int(round(m) + 1/60) # addition of 1 second to circumvent rounding problems if m == 1440: retval = int(jd) + 1 else: retval = int(jd) + m / (24 * 60) return retval def moonDistance(jd): T = julianCenturiesSince2000(jd) LM = 218.3164591 + 481267.88134236 * T - 0.0013268 * T**2 + T**3 / 538841 - T**4/65194000 D = 297.8502042 + 445267.1115168 * T - 0.00163 * T**2 + T**3 / 545868 - T**4 / 113065000 M = 357.5291092 + 35999.0502909 * T - 0.0001536 * T**2 + T**3 / 24490000 MM = 134.9634114 + 477198.8676313 * T + 0.0089970 * T**2 + T**3 / 69699 - T**4 / 14712000 F = 93.2720993 + 483202.0175273 * T - 0.0034029 * T**2 - T**3 / 3526000 + T**4/863310000 terms = [[ 0,0,1,0,-20905355 ], [ 2,0,-1,0,-3699111 ], [ 2,0,0,0,-2955968 ], [ 0,0,2,0,-569925 ], [ 0,1,0,0,48888 ], [ 0,0,0,2,-3149 ], [ 2,0,-2,0,246158 ], [ 2,-1,-1,0,-152138 ], [ 2,0,1,0,-170733 ], [ 2,-1,0,0,-204586 ], [ 0,1,-1,0,-129620 ], [ 1,0,0,0,108743 ], [ 0,1,1,0,104755 ], [ 2,0,0,-2,10321 ], [ 0,0,1,-2,79661 ], [ 4,0,-1,0,-34782 ], [ 0,0,3,0,-23210 ], [ 4,0,-2,0,-21636 ], [ 2,1,-1,0,24208 ], [ 2,1,0,0,30824 ], [ 1,0,-1,0,-8379 ], [ 1,1,0,0,-16675 ], [ 2,-1,1,0,-12831 ], [ 2,0,2,0,-10445 ], [ 4,0,0,0,-11650 ], [ 2,0,-3,0,14403 ], [ 0,1,-2,0,-7003 ], [ 2,-1,-2,0,10056 ], [ 1,0,1,0,6322 ], [ 2,-2,0,0,-9884 ], [ 0,1,2,0,5751 ], [ 2,-2,-1,0,-4950 ], [ 2,0,1,-2,4130 ], [ 4,-1,-1,0,-3958 ], [ 3,0,-1,0,3258 ], [ 2,1,1,0,2616 ], [ 4,-1,-2,0,-1897 ], [ 0,2,-1,0,-2117 ], [ 2,2,-1,0,2354 ], [ 4,0,1,0,-1423 ], [ 0,0,4,0,-1117 ], [ 4,-1,0,0,-1571 ], [ 1,0,-2,0,-1739 ], [ 0,0,2,-2,-4421 ], [ 0,2,1,0,1165 ], [ 2,0,-1,-2,8752 ]] R = 0 for row in terms: E = 1 if abs(row[1]) <= 2: E = earthEccentricity(jd) if abs(row[2]) == 2: E = E**2 R += COS(row[0] * D + row[1] * M + row[2] * MM + row[3] * F) * row[4] * E return round(385000.56 + R / 1000, 1) def moonPhase(k): T = k / 1236.85 jd = 2451550.09765 + 29.530588853 * k + 0.0001337 * T**2 - 0.000000150 * T**3 + 0.00000000073 * T**4 E = earthEccentricity(jd) M = (2.5534 + 29.10535669 * k - 0.0000218 * T**2 - 0.00000011 * T**3) % 360 MM = (201.5643 + 385.81693528 * k + 0.0107438 * T**2 + 0.00001239 * T**3 - 0.000000058 * T**4) % 360 F = (160.7108 + 390.67050274 * k - 0.0016341 * T**2 - 0.00000227 * T**3 + 0.000000011 * T**4) % 360 AN = (124.7746 - 1.5637558 * k + 0.0020691 * T**2 + 0.00000215 * T**3) % 360 phase = abs(frac(k)) match phase: case 0: # Neumond corr = [ -0.4072, 0.17241*E, 0.01608, 0.01039, 0.00739*E, -0.00514*E, 0.00208*E**2, -0.00111, -0.00057, 0.00056*E, -0.00042, 0.00042*E, 0.00038*E, -0.00024*E, -0.00017, -0.00007, 0.00004, 0.00004, 0.00003, 0.00003, -0.00003, 0.00003, -0.00002, -0.00002, 0.00002 ] case 0.5: # Vollmond corr = [ -0.40614, 0.17302*E, 0.01614, 0.01043, 0.00734*E, -0.00515*E, 0.00209*E**2, -0.00111, -0.00057, 0.00056*E, -0.00042, 0.00042*E, 0.00038*E, -0.00024*E, -0.00017, -0.00007, 0.00004, 0.00004, 0.00003, 0.00003, -0.00003, 0.00003, -0.00002, -0.00002, 0.00002 ] case 0.25 | 0.75: # 1. & 3. Viertel corr = [ -0.62801, 0.17172*E, -0.01183*E, 0.00862, 0.00804, 0.00454*E, 0.00204*E**2, -0.0018, -0.0007, -0.0004, -0.00034*E, 0.00032*E, 0.00032*E, -0.00028*E**2, 0.00027*E, -0.00017, -0.00005, 0.00004, -0.00004, 0.00004, 0.00003, 0.00003, 0.00002, 0.00002, -0.00002 ] case _: return 0, 0 match phase: case 0 | 0.5: # Neumond, Vollmond correction = corr[0] * SIN(MM) + corr[1] * SIN(M) + corr[2] * SIN(2*MM) + corr[3] * SIN(2*F) + corr[4] * SIN(MM-M) + \ corr[5] * SIN(MM+M) + corr[6] * SIN(2*M) + corr[7] * SIN(MM-2*F) + corr[8] * SIN(MM+2*F) + corr[9] * SIN(2*MM+M) + \ corr[10] * SIN(3*MM) + corr[11] * SIN(M+2*F) + corr[12] * SIN(M-2*F) + corr[13] * SIN(2*MM-M) + corr[14] * SIN(AN) + \ corr[15] * SIN(MM+2*M) + corr[16] * SIN(2*MM-2*F) + corr[17] * SIN(3*M) + corr[18] * SIN(MM+M-2*F) + corr[19] * SIN(2*MM+2*F) + \ corr[20] * SIN(MM+M+2*F) + corr[21] * SIN(MM-M+2*F) + corr[22] * SIN(MM-M-2*F) + corr[23] * SIN(3*MM+M) + corr[24] * SIN(4*MM) case 0.25 | 0.75: # 1. & 3. Viertel correction = corr[0] * SIN(MM) + corr[1] * SIN(M) + corr[2] * SIN(MM+M) + corr[3] * SIN(2*MM) + corr[4] * SIN(2*F) + \ corr[5] * SIN(MM-M) + corr[6] * SIN(2*M) + corr[7] * SIN(MM-2*F) + corr[8] * SIN(MM+2*F) + corr[9] * SIN(3*MM) + \ corr[10] * SIN(2*MM-M) + corr[11] * SIN(M+2*F) + corr[12] * SIN(M-2*F) + corr[13] * SIN(MM+2*M) + corr[14] * SIN(2*MM+M) + \ corr[15] * SIN(AN) + corr[16] * SIN(MM-M-2*F) + corr[17] * SIN(2*MM+2*F) + corr[18] * SIN(MM+M+2*F) + corr[19] * SIN(MM-2*M) + \ corr[20] * SIN(MM+M-2*F) + corr[21] * SIN(3*M) + corr[22] * SIN(2*MM-2*F) + corr[23] * SIN(MM-M+2*F) + corr[24] * SIN(3*MM+M) W = 0.00306 - 0.00038 * E * COS(M) + 0.00026 * COS(MM) - 0.00002 * COS(MM-M) + 0.00002 * COS(MM + M) + 0.00002 * COS(2 * F) if phase == 0.25: correction = correction + W else: correction = correction - W jd_final = jd + correction distance = moonDistance(jd_final) return roundJD(jd_final), distance def validDate(s): try: return datetime.strptime(s, "%Y-%m-%d") except ValueError: raise argparse.ArgumentTypeError(f"Invalid date format: {s}. Use YYYY-MM-DD format.") def createICSCalendar(filename, startk, endk, fullcalc, timezone='Europe/Berlin', reminder_days=0): cal = Calendar() cal.add('prodid', '-//Mondphasen Kalender//') cal.add('version', '2.0') cal.add('X-WR-CALNAME', 'Mondphasen Kalender') cal.add('X-WR-TIMEZONE', timezone) tz = pytz.timezone(timezone) for k in range(startk, endk + 1): # Neumond jd, d = moonPhase(k) event = Event() event.add('summary', 'Neumond') dt_start = jd2date(jd).astimezone(tz) # Zeitzonenbereinigter Zeitpunkt dt_end = dt_start + timedelta(hours=1) event.add('dtstart', dt_start) event.add('dtend', dt_end) event['dtstart'].params['TZID'] = timezone event['dtend'].params['TZID'] = timezone event.add('description', f'Neumond: {jd2date(jd).strftime("%Y-%m-%d %H:%M")} ME(S)Z\nEntfernung: {d} km') event.add('dtstamp', datetime.now(tz)) # Erinnerung hinzufügen if reminder_days > 0: alarm = createAlarm(reminder_days) event.add_component(alarm) cal.add_component(event) # 1. Viertel if fullcalc: jd, d = moonPhase(k + 0.25) event = Event() event.add('summary', '1. Viertel') dt_start = jd2date(jd).astimezone(tz) # Zeitzonenbereinigter Zeitpunkt dt_end = dt_start + timedelta(hours=1) event.add('dtstart', dt_start) event.add('dtend', dt_end) event['dtstart'].params['TZID'] = timezone event['dtend'].params['TZID'] = timezone event.add('description', f'Zunehmendes Viertel: {jd2date(jd).strftime("%Y-%m-%d %H:%M")} ME(S)Z\nEntfernung: {d} km') event.add('dtstamp', datetime.now(tz)) if reminder_days > 0: alarm = createAlarm(reminder_days) event.add_component(alarm) cal.add_component(event) # Vollmond jd, d = moonPhase(k + 0.5) nstr = 'Vollmond' if d >= 360000 else 'Supermond' event = Event() event.add('summary', nstr) dt_start = jd2date(jd).astimezone(tz) # Zeitzonenbereinigter Zeitpunkt dt_end = dt_start + timedelta(hours=1) event.add('dtstart', dt_start) event.add('dtend', dt_end) event['dtstart'].params['TZID'] = timezone event['dtend'].params['TZID'] = timezone event.add('description', f'{nstr}: {jd2date(jd).strftime("%Y-%m-%d %H:%M")} ME(S)Z\nEntfernung: {d} km') event.add('dtstamp', datetime.now(tz)) if reminder_days > 0: alarm = createAlarm(reminder_days) event.add_component(alarm) cal.add_component(event) # 3. Viertel if fullcalc: jd, d = moonPhase(k + 0.75) event = Event() event.add('summary', '3. Viertel') dt_start = jd2date(jd).astimezone(tz) # Zeitzonenbereinigter Zeitpunkt dt_end = dt_start + timedelta(hours=1) event.add('dtstart', dt_start) event.add('dtend', dt_end) event['dtstart'].params['TZID'] = timezone event['dtend'].params['TZID'] = timezone event.add('description', f'Abnehmendes Viertel: {jd2date(jd).strftime("%Y-%m-%d %H:%M")} ME(S)Z\nEntfernung: {d} km') event.add('dtstamp', datetime.now(tz)) if reminder_days > 0: alarm = createAlarm(reminder_days) event.add_component(alarm) cal.add_component(event) # ICS-Datei speichern with open(filename, 'wb') as f: f.write(cal.to_ical()) def createAlarm(reminder_days): """Erstellt eine Erinnerung als VALARM, die reminder_days vor dem Event erinnert.""" alarm = Alarm() alarm.add('ACTION', 'DISPLAY') alarm.add('DESCRIPTION', 'Mondphasen Erinnerung') alarm.add('TRIGGER', timedelta(days=-reminder_days)) return alarm if __name__ == "__main__": startdate_default = datetime.now() enddate_default = datetime(startdate_default.year + 10, startdate_default.month, startdate_default.day) - timedelta(days=1) parser = argparse.ArgumentParser(description='Berechne Mondphasen; Ausgabe in stdout, CSV, TXT oder ICS') parser.add_argument('-b', '--beginn', type=validDate, default=startdate_default, help=f'Startdatum für Mondphasen (Format: YYYY-MM-DD). Default: {startdate_default.strftime("%Y-%m-%d")}') parser.add_argument('-e', '--ende', type=validDate, default=enddate_default, help=f'Enddatum für Mondphasen (Format: YYYY-MM-DD). Default: {enddate_default.strftime("%Y-%m-%d")}') parser.add_argument('-a', '--alle-phasen', action='store_true', default=False, help='Alle Mondphasen einbeziehen (inklusive Halbmonde). Standard: nur Neumond und Vollmond.') parser.add_argument('-o', '--output', default=sys.stdout, help='Output file name (default: stdout)') parser.add_argument('-r', '--reminder', type=int, default=0, help='Anzahl der Tage vorher für eine Erinnerung. Default: 0 (keine Erinnerung).') parser.add_argument('-z', '--timezone', type=str, default='Europe/Berlin', help="Zeitzone für die Termine, Default 'Europe/Berlin'. Für gültige Zeitzonen siehe: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones") args = parser.parse_args() startdate = args.beginn enddate = args.ende fullcalc = args.alle_phasen output_filename = args.output if output_filename != sys.stdout: if output_filename.lower() == 'stdout': output_filename = sys.stdout elif not output_filename.lower().endswith(".csv") and not output_filename.lower().endswith(".ics") and not output_filename.lower().endswith(".txt"): print("Gültige Ausgabeformate: stdout, CSV, TXT, ICS (z.B. out.csv, out.txt, out.ics)") sys.exit(1) # Erinnerungstage prüfen und sicherstellen, dass es eine positive Zahl oder 0 ist try: reminder = int(args.reminder) if reminder < 0: print("Die Anzahl der Erinnerungstage muss eine positive Zahl oder 0 sein.") sys.exit(1) except ValueError: print("Ungültiger Wert für die Anzahl der Erinnerungstage. Bitte eine ganze Zahl angeben.") sys.exit(1) if output_filename == sys.stdout or not output_filename.lower().endswith(".ics"): if reminder != 0: print("Fehler: Erinnerung kann nur für Ausgabe in ICS-Datei gesetzt werden.") sys.exit(1) # Überprüfen, ob die angegebene Zeitzone gültig ist try: tz = pytz.timezone(args.timezone) except pytz.UnknownTimeZoneError: print(f"Unbekannte Zeitzone: {args.timezone}. Bitte eine gültige Zeitzone angeben.") sys.exit(1) TIMEZONE=args.timezone startk = previousNewMoon_k(startdate) endk = previousNewMoon_k(enddate) # Beginn ist der erste Neumond NACH dem startdate # Ausgegeben wird jedoch immer ein vollständiger Zyklus, so dass Ausgaben auch nach # enddate liegen können, falls dessen Neumond vor enddate gefallen ist jd, d = moonPhase(startk) if jd < date2jd(startdate): startk += 1 if fullcalc: addstr = ' ' else: addstr = '' if output_filename != sys.stdout and output_filename.lower().endswith(".ics"): createICSCalendar(output_filename, startk, endk, fullcalc, timezone=TIMEZONE, reminder_days=reminder) else: for k in range(startk, endk + 1): if output_filename == sys.stdout: jd, d = moonPhase(k) print ("Neumond: " + addstr + jd2date(jd).strftime("%Y-%m-%d %H:%M") + " ME(S)Z / Entfernung: " + str(d)) if fullcalc: jd, d = moonPhase(k + 0.25) print ("1.Viertel: " + jd2date(jd).strftime("%Y-%m-%d %H:%M") + " ME(S)Z / Entfernung: " + str(d)) jd, d = moonPhase(k + 0.5) nstr = "Vollmond:" if d >= 360000 else "VOLLMOND!" print (nstr + " " + addstr + jd2date(jd).strftime("%Y-%m-%d %H:%M") + " ME(S)Z / Entfernung: " + str(d)) if fullcalc: jd, d = moonPhase(k + 0.75) print ("3.Viertel: " + jd2date(jd).strftime("%Y-%m-%d %H:%M") + " ME(S)Z / Entfernung: " + str(d)) if k != endk: print() elif output_filename.lower().endswith(".csv"): with open(output_filename, mode='w', newline='') as file: writer = csv.writer(file, delimiter=';') writer.writerow(["Phase", "Datum", "Uhrzeit ME(S)Z", "Entfernung (km)"]) for k in range(startk, endk + 1): jd, d = moonPhase(k) writer.writerow(["Neumond", jd2date(jd).strftime("%Y-%m-%d"), jd2date(jd).strftime("%H:%M"), str(d).replace('.', ',')]) if fullcalc: jd, d = moonPhase(k + 0.25) writer.writerow(["Zunehmendes Viertel", jd2date(jd).strftime("%Y-%m-%d"), jd2date(jd).strftime("%H:%M"), str(d).replace('.', ',')]) jd, d = moonPhase(k + 0.5) nstr = "Vollmond" if d >= 360000 else "Supermond" writer.writerow([nstr, jd2date(jd).strftime("%Y-%m-%d"), jd2date(jd).strftime("%H:%M"), str(d).replace('.', ',')]) if fullcalc: jd, d = moonPhase(k + 0.75) writer.writerow(["Abnehmendes Viertel", jd2date(jd).strftime("%Y-%m-%d"), jd2date(jd).strftime("%H:%M"), str(d).replace('.', ',')]) elif output_filename.lower().endswith(".txt"): with open(output_filename, mode='w', newline='') as file: file.write("Phase\tDatum\tUhrzeit ME(S)Z\tEntfernung (km)\n") for k in range(startk, endk + 1): jd, d = moonPhase(k) file.write(f"Neumond\t{jd2date(jd).strftime('%Y-%m-%d')}\t{jd2date(jd).strftime('%H:%M')}\t{d}\n") if fullcalc: jd, d = moonPhase(k + 0.25) file.write(f"Zunehmendes Viertel\t{jd2date(jd).strftime('%Y-%m-%d')}\t{jd2date(jd).strftime('%H:%M')}\t{d}\n") jd, d = moonPhase(k + 0.5) nstr = "Vollmond" if d >= 360000 else "Supermond" file.write(f"{nstr}\t{jd2date(jd).strftime('%Y-%m-%d')}\t{jd2date(jd).strftime('%H:%M')}\t{d}\n") if fullcalc: jd, d = moonPhase(k + 0.75) file.write(f"Abnehmendes Viertel\t{jd2date(jd).strftime('%Y-%m-%d')}\t{jd2date(jd).strftime('%H:%M')}\t{d}\n")