#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
import os
import sys
import math
PWD = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.dirname(os.path.dirname(PWD))
sys.path.append(BASE_DIR)
from badidatetime import BahaiCalendar, GregorianCalendar
[docs]
class JulianPeriodTests:
JULIAN_YEAR = 365.25
GREGORIAN_EPOCH = 1721423.5
MEAN_TROPICAL_YEAR = 365.2421897
#MEAN_SIDEREAL_YEAR = 365.256363004
ROUNDING_PLACES = 6
JULIAN_LEAP_YEAR = lambda self, year: year % 4 == 0
MONTHS = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
HR = lambda self, x: x / 24
MN = lambda self, x: x / 24 / 60
SEC = lambda self, x: x / 24 / 60 / 60
TEST_DATES = (
(-4712, 1, 1.5),
(1, 1, 1),
(1, 3, 20),
(2, 1, 1), (3, 1, 1), (4, 1, 1),
(4, 12, 31), (5, 1, 1),
(6, 1, 1), (8, 1, 1), (9, 1, 1),
# The 29th should be wrong for standard leap year
(100, 2, 28), (100, 2, 29), (100, 3, 1),
# The 29th should be wrong for alternative leap year
(128, 2, 28), (128, 2, 29), (128, 3, 1),
# The 29th should be wrong for standard leap year
(200, 2, 28), (200, 2, 29), (200, 3, 1),
# The 29th should be wrong for alternative leap year
(256, 2, 28), (256, 2, 29), (256, 3, 1),
# The 29th should be wrong for standard leap year
(300, 2, 28), (300, 2, 29), (300, 3, 1),
# The 29th should be wrong for alternative leap year
(384, 2, 28), (384, 2, 29), (384, 3, 1),
# The 29th should be wrong for standard leap year
(400, 2, 28), (400, 2, 29), (400, 3, 1),
(800, 1, 1), (800, 12, 31),
(1200, 1, 1), (1200, 12, 31),
(1300, 1, 1), (1300, 12, 31),
(1400, 1, 1), (1400, 12, 31),
(1500, 1, 1), (1500, 12, 31),
(1582, 10, 4), (1582, 10, 5), (1582, 10, 6), (1582, 10, 7),
(1582, 10, 8), (1582, 10, 9), (1582, 10, 10), (1582, 10, 11),
(1582, 10, 12), (1582, 10, 13), (1582, 10, 14), (1582, 10, 15),
(1844, 3, 20),
(1957, 10, 4.81),
(2020, 12, 7), (2020, 12, 7.1), (2020, 12, 7.25), (2020, 12, 7.49),
(2020, 12, 8),
(2024, 3, 20),
(3004, 12, 31),
# Off by one issue
## (100, 12, 30), (100, 12, 31),
## (101, 1, 1), (101, 1, 2), (101, 12, 30), (101, 12, 31),
## (102, 1, 1), (102, 1, 2), (102, 12, 30), (102, 12, 31),
## (104, 1, 1), (108, 1, 1),
## (200, 12, 30), (200, 12, 31),
## (201, 1, 1), (201, 1, 2),
## (300, 12, 30), (300, 12, 31),
## (301, 1, 1), (301, 1, 2),
## (400, 12, 30), (400, 12, 31),
## (401, 1, 1), (401, 1, 2),
## # The 29th should be wrong for standard leap year
## (500, 2, 28), (500, 2, 29), (500, 3, 1),
## (500, 12, 30), (500, 12, 31),
## (501, 1, 1), (501, 7, 1),
## (600, 12, 30), (600, 12, 31),
## (601, 1, 1),
## # The 29th should be wrong for standard leap year
## (700, 2, 28), (700, 2, 29), (700, 3, 1),
## (700, 12, 30), (700, 12, 31),
## (701, 1, 1),
## (800, 12, 30), (800, 12, 31),
## (801, 1, 1), (801, 1, 2),
## # The 29th should be wrong for standard leap year
## (900, 2, 28), (900, 2, 29), (900, 3, 1),
## (900, 12, 31), (901, 1, 1), (901, 1, 2),
## # The 29th should be wrong for standard leap year
## (1000, 2, 28), (1000, 2, 29), (1000, 3, 1),
## (1000, 12, 31), (1001, 1, 1),
## # The 29th should be wrong for standard leap year
## (1100, 2, 28), (1100, 2, 29), (1100, 3, 1),
## (1100, 12, 31), (1101, 1, 1), #(1100, 1, 2),
## (1200, 12, 31), (1201, 1, 1), (1201, 1, 2),
## (2024, 1, 1), (2024, 1, 2), (2024, 1, 3),
## # The 29th should be wrong for standard leap year
## (1300, 2, 28), (1300, 2, 29), (1300, 3, 1),
## (1300, 12, 31), (1301, 1, 1),
## (1400, 12, 31), (1401, 1, 1),
## (1500, 12, 31), (1501, 1, 1),
## # The 29th should be wrong for standard leap year
## (1500, 2, 28), (1500, 2, 29), (1500, 3, 1),
## (1600, 12, 31), (1601, 1, 1),
## (1700, 12, 31), (1701, 1, 1), # 11
## (1800, 12, 31), (1801, 1, 1), # 12
## (1900, 12, 31), (1901, 1, 1), # 13
## (2000, 1, 1, 12),
## (2000, 12, 31), (2001, 1, 1), # 13
## (2100, 12, 31), (2101, 1, 1), # 14
## (2200, 12, 31), (2201, 1, 1), # 15
## (2300, 12, 31), (2301, 1, 1), # 16
## (2400, 12, 31), (2401, 1, 1), # 16
## (2500, 12, 31), (2501, 1, 1), # 17
## (2600, 12, 31), (2601, 1, 1), # 18
## (2700, 12, 31), (2701, 1, 1), # 19
## (2800, 12, 31), (2801, 1, 1), # 19
## (2900, 12, 31), (2901, 1, 1), # 20
## (3000, 12, 31), (3001, 1, 1), # 21
## (3100, 12, 31), (3101, 1, 1), # 22
## (3200, 12, 31), (3201, 1, 1),
)
def __init__(self):
self._bc = BahaiCalendar()
self._gc = GregorianCalendar()
[docs]
def analyze(self, options):
"""
Check that Gregorian dates can be converted to a Julian Period
day then back to a Gregorian dates correctly.
-a with optional -A for alternate leap year calculation.
"""
data = []
for date in self.TEST_DATES:
date = date if isinstance(date, tuple) else (date, 1, 1)
leap = self._gc._is_leap_year(date[0], alt=options.alt_leap)
jd0 = self.jd_from_gregorian_date_0(date)
jd1 = self.jd_from_gregorian_date_1(date, alt=options.alt_leap)
if not options.alt_leap and date[1:] == (2, 29) and not leap:
gd0 = 'INVALID'
else:
gd0 = self.gregorian_date_from_jd_0(jd0)
if date[1:] == (2, 29) and not leap:
gd1 = 'INVALID'
else:
gd1 = self.gregorian_date_from_jd_1(jd1, alt=options.alt_leap)
# Meeus Mine
data.append((date, leap, jd0, gd0, jd1, gd1))
return data
[docs]
def analyze_1(self, options):
"""
Compare Meeus' and my algorithms showing differences.
| -1 with optional -A for alternate leap year calculation.
| -S and -E are mandatory.
If the last column shows anything other than 0.0 then there are
inconsistencies.
This test will display, to stderr a progress counter indicating
every 500 years.
"""
data = []
for year in range(options.start, options.end):
leap = self._gc._is_leap_year(year, alt=options.alt_leap)
for month, days in enumerate(self.MONTHS, start=1):
max_days = days + leap
for day in range(1, max_days + 1):
date = (year, month, day)
jd0 = self.jd_from_gregorian_date_0(date)
gd0 = self.gregorian_date_from_jd_0(jd0)
jd1 = self.jd_from_gregorian_date_1(
date, alt=options.alt_leap)
gd1 = self.gregorian_date_from_jd_1(
jd1, alt=options.alt_leap)
data.append((date, leap, jd0, gd0, jd1, gd1))
if year % 500 == 0 and month == 1 and day == 1:
print(date, file=sys.stderr)
return data
[docs]
def analyze_2(self, options):
"""
Check that any Gregorian date can be converted to a Julian Period
day and then back again to a Gregorian date correctly.
This only tests my algorithm.
If there is any data returned except the heading then there are
errors in the conversion.
| -2 with optional -A for alternate leap year calculation.
| -S and -E are mandatory.
This test will display, to stderr a progress counter indicating
every 500 years.
"""
data = []
for year in range(options.start, options.end):
leap = self._gc._is_leap_year(year, alt=options.alt_leap)
for month, days in enumerate(self.MONTHS, start=1):
max_days = days + leap
for day in range(1, max_days + 1):
date = (year, month, day)
jd1 = self.jd_from_gregorian_date_1(
date, alt=options.alt_leap)
gd1 = self.gregorian_date_from_jd_1(
jd1, alt=options.alt_leap)
if date != gd1:
data.append((date, gd1, jd1, leap))
if year % 500 == 0 and month == 1 and day == 1:
print(date, file=sys.stderr)
return data
[docs]
def compare_leap_year_algorithms(self, year=None):
"""
Compare the two leap year algorithms.
| If -c == 0 then all dates from 1 to 3004 are processed.
| If -c == any year, then only that year is processed.
The table below shows the differences between the 4, 10, 400 and
4, 128 algorithms. Notice that the dates up to 1482-10-15 are not
in sync with each other.
+------+------------+--------+-----+-----+
| Year | 4, 10, 400 | 4, 128 | std | alt |
+======+============+========+=====+=====+
| 100 | 0 | 1 | 1 | |
+------+------------+--------+-----+-----+
| 128 | 1 | 0 | | 1 |
+------+------------+--------+-----+-----+
| 200 | 0 | 1 | 2 | |
+------+------------+--------+-----+-----+
| 256 | 1 | 0 | | 2 |
+------+------------+--------+-----+-----+
| 300 | 0 | 1 | 3 | |
+------+------------+--------+-----+-----+
| 384 | 1 | 0 | | 3 |
+------+------------+--------+-----+-----+
| 500 | 0 | 1 | 4 | |
+------+------------+--------+-----+-----+
| 512 | 1 | 0 | | 4 |
+------+------------+--------+-----+-----+
| 600 | 0 | 1 | 5 | |
+------+------------+--------+-----+-----+
| 640 | 1 | 0 | | 5 |
+------+------------+--------+-----+-----+
| 700 | 0 | 1 | 6 | |
+------+------------+--------+-----+-----+
| 768 | 1 | 0 | | 6 |
+------+------------+--------+-----+-----+
| 896 | 1 | 0 | | 7 |
+------+------------+--------+-----+-----+
| 900 | 0 | 1 | 7 | |
+------+------------+--------+-----+-----+
| 1000 | 0 | 1 | 8 | |
+------+------------+--------+-----+-----+
| 1024 | 1 | 0 | | 8 |
+------+------------+--------+-----+-----+
| 1100 | 0 | 1 | 9 | |
+------+------------+--------+-----+-----+
| 1152 | 1 | 0 | | 9 |
+------+------------+--------+-----+-----+
| 1280 | 1 | 0 | | 10 |
+------+------------+--------+-----+-----+
| 1300 | 0 | 1 | 10 | |
+------+------------+--------+-----+-----+
| 1400 | 0 | 1 | 11 | |
+------+------------+--------+-----+-----+
| 1408 | 1 | 0 | | 11 |
+------+------------+--------+-----+-----+
| 1500 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 1536 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 1664 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 1700 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 1792 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 1800 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 1900 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 1920 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 2048 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 2100 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 2176 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 2200 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 2300 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 2304 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 2432 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 2500 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 2560 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 2600 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 2688 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 2700 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 2816 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 2900 | 0 | 1 | | |
+------+------------+--------+-----+-----+
| 2944 | 1 | 0 | | |
+------+------------+--------+-----+-----+
| 3000 | 0 | 1 | | |
+------+------------+--------+-----+-----+
"""
data = []
if year <= 0:
for y in range(1, 3005):
y0 = self._gc._is_leap_year(y)
y1 = self._gc._is_leap_year(y, alt=True)
if y0 != y1:
data.append((y, y0, y1))
else:
y0 = self._gc._is_leap_year(y)
y1 = self._gc._is_leap_year(y, alt=True)
data.append((year, y0, y1))
return data
[docs]
def consecutive_days(self, options):
"""
Test that the Julian Period days are consecutive. i.e. no skipping
or doubling up.
Should produce no output if working correctly.
| -k With optional -A for alternate leap year calculation.
| -S and -E are mandatory.
| If -J is used then the test is for consecutive Julian Period days.
| If -JM is used the test is for consecutive Julian Period days using
| Meeus' algorithm.
| If -G is used the test is for consecutive Julian Period days using
| my algorithm.
Some tests will display, to stderr a progress counter indicating
every 500 years.
"""
method = (self.jd_from_gregorian_date_0 if options.meeus else
self.jd_from_gregorian_date_1)
data = []
last_jd = 0
if options.julian:
for year in range(options.start, options.end):
for month, days in enumerate(self.MONTHS, start=1):
if (year, month) >= (1582, 10) or options.meeus:
leap = self._gc._is_leap_year(
year, alt=options.alt_leap)
else:
leap = self.JULIAN_LEAP_YEAR(year)
max_days = days + leap
for day in range(1, max_days + 1):
date = (year, month, day)
jd = method(date, alt=options.alt_leap)
if last_jd != 0 and last_jd == jd:
data.append((date, last_jd, jd))
last_jd = jd # Save the jd
elif options.g_date:
items = []
last_date = ()
month_days = list(self.MONTHS)
for year in range(options.start, options.end):
leap = self._gc._is_leap_year(year, alt=options.alt_leap)
month_days[1] = 29 if leap else 28
for month, days in enumerate(month_days, start=1):
for day in range(1, days+1):
items.append((year, month, day))
for item in items:
# My algorithms
jd = self.jd_from_gregorian_date_1(item, alt=options.alt_leap)
date = self.gregorian_date_from_jd_1(jd, alt=options.alt_leap)
if last_jd != 0 and (last_jd == jd or item != date):
data.append((last_date, last_jd, item, jd, date))
last_jd = jd
last_date = date
if item[0] % 500 == 0 and item[1] == 1 and item[2] == 1:
print(item, file=sys.stderr)
return data
[docs]
def julian_day_with_ut_sunset(self, options):
"""
Generate a list of Julian days with ut sunset data. This must be done
in the historically correct Julian day count or the sunsets will
not be correct.
Sunsets found on https://gml.noaa.gov/grad/solcalc/ set to UTC
coordinates.
The output is used in some Badí tests.
-j with -S and -E which are mandatory.
"""
data = []
hm = {
(1, 3, 19): (18, 11),
(1, 3, 20): (18, 12),
(1, 4, 8): (18, 42),
(2, 2, 24): (17, 33),
(2, 2, 25): (17, 34),
(2, 2, 26): (17, 36),
(2, 3, 2): (17, 43),
(2, 3, 6): (17, 49),
(1583, 3, 20): (18, 12),
(1583, 3, 21): (18, 14),
(1844, 3, 19): (18, 12),
(1845, 3, 20): (18, 13),
(1863, 3, 20): (18, 12),
(1863, 3, 21): (18, 14),
(1970, 1, 1): ( 0, 0),
(2015, 3, 20): (18, 12),
(2015, 3, 21): (18, 14),
(2022, 2, 24): (17, 31),
(2022, 2, 25): (17, 33),
(2022, 3, 1): (17, 40),
(2022, 3, 2): (17, 42),
(2024, 3, 19): (17, 12),
(2024, 3, 20): (18, 14),
(2024, 4, 20): (19, 6),
(2024, 5, 12): (19, 41),
(2024, 5, 14): (19, 45),
(2024, 7, 17): (20, 8),
}
for year in range(options.start, options.end):
leap = (self.JULIAN_LEAP_YEAR(year) if year < 1583
else self._gc._is_leap_year(year))
lat, lon = (51.477928, -0.001545)
for month, days in enumerate(self.MONTHS, start=1):
max_days = days + leap
for day in range(1, max_days + 1):
date = (year, month, day)
date += hm[date] if date in hm else ()
try:
jd_ut = self._gc.jd_from_gregorian_date(date)
except AssertionError:
print((year, month, day))
continue
jd_ss_ut = self._gc._sun_setting(jd_ut, lat, lon)
# Convert to Astronomically correct jd.
ajd = self._gc.jd_from_gregorian_date(date, exact=True)
ss = math.floor(ajd) + jd_ss_ut % 1
data.append((date, ss))
return data
# Supporting methods
[docs]
def jd_from_gregorian_date_0(self, g_date, alt=False):
"""
The JDs below are all in the Meeus Histroically correct algorithm.
The alt keyword does nothing.
| US Naval Observatory Julian Date page:
| https://aa.usno.navy.mil/data/JulianDate
There are 12 years that skip a day. Pope Gregory only compensated
for 10 of them. The JDs below are all in the non-proleptic historic
(Meeus) algorithm and signify the beginning of the day.
.. csv-table:: Gregorian JD offsets
:header: "Valid or Invalid Day(s)", \
"Valid Day JD", \
"Next Valid or Invalid Day(s)", \
"Next Valid Day JD", \
"Offset"
:widths: 21, 16, 26, 24, 13
"(100, 2, 28)", 1757640.5, "(100, 3, 1)", 1757642.5, 1
"(100, 2, 29)", 1757641.5, "Invalid", "", ""
"(200, 2, 28)", 1794165.5, "(200, 3, 1)", 1794167.5, 2
"(200, 2, 29)", 1794166.5, "Invalid", "", ""
"(300, 2, 28)", 1830690.5, "(300, 3, 1)", 1830692.5, 3
"(300, 2, 29)", 1830691.5, "Invalid", "", ""
"(500, 2, 28)", 1903740.5, "(500, 3, 1)", 1903742.5, 4
"(500, 2, 29)", 1903741.5, "Invalid", "", ""
"(600, 2, 28)", 1940265.5, "(600, 3, 1)", 1940267.5, 5
"(600, 2, 29)", 1940266.5, "Invalid", "", ""
"(700, 2, 28)", 1976790.5, "(700, 3, 1)", 1976792.5, 6
"(700, 2, 29)", 1976791.5, "Invalid", "", ""
"(900, 2, 28)", 2049840.5, "(900, 3, 1)", 2049842.5, 7
"(900, 2, 29)", 2049841.5, "Invalid", "", ""
"(1000, 2, 28)", 2086365.5, "(1000, 3, 1)", 2086367.5, 8
"(1000, 2, 29)", 2086366.5, "Invalid", "", ""
"(1100, 2, 28)", 2122890.5, "(1100, 3, 1)", 2122892.5, 9
"(1100, 2, 29)", 2122891.5, "Invalid", "", ""
"(1300, 2, 28)", 2195940.5, "(1300, 3, 1)", 2195942.5, 10
"(1300, 2, 29)", 2195941.5, "Invalid", "", ""
"(1400, 2, 28)", 2232465.5, "(1400, 3, 1)", 2232467.5, 11
"(1400, 2, 29)", 2232466.5, "Invalid", "", ""
"(1500, 2, 28)", 2268990.5, "(1500, 3, 1)", 2268992.5, 12
"(1500, 2, 29)", 2268991.5, "Invalid", "", ""
"(1582, 10, 4)", 2299159.5, "(1582, 10, 15)", 2299160.5, ""
"(1582, 10, 5) to (1582, 10, 14)", "2299160.5 to 2299169.5", \
"Invalid", "Only adjusted 10 days", ""
"(1582, 10, 15)", 2299160.5, "(1582, 10, 16)", 2299161.5, 2
"""
year, month, day = self.date_from_ymdhms(g_date)
if month <= 2:
year -= 1
month += 12
if (year, month, day) >= (1582, 10, 15):
a = math.floor(year / 100)
b = 2 - a + math.floor(a / 4)
else:
b = 0
return round(math.floor(self.JULIAN_YEAR * year) + math.floor(
30.6001 * (month + 1)) + day + b + 1720994.5, self.ROUNDING_PLACES)
[docs]
def jd_from_gregorian_date_1(self, g_date, alt=False):
"""
My algorithm
"""
year, month, day = self.date_from_ymdhms(g_date)
td = self._days_in_years(year-1, alt=alt)
days = td + (self.GREGORIAN_EPOCH - 1) # 37
month_days = list(self.MONTHS)
leap = self._gc._is_leap_year(year, alt=options.alt_leap)
month_days[1] = 29 if leap else 28
days += sum(month_days[:month-1]) + day
# print(f"date: {str(g_date):<16} td: {td:<8} "
# f"days: {days:<10} "
# f"sum: {sum(month_days[:month-1]):<10}\n", file=sys.stderr)
return days
[docs]
def gregorian_date_from_jd_0(self, jd):
"""
Convert Julian day to Gregorian date using the Meeus algorithm.
"""
j_day = jd + 0.5
z = math.floor(j_day)
f = j_day % 1
if z >= 2299161: # 1582-10-15 Julian and Gregorian crossover.
alpha = math.floor((z - 1867216.25) / 36524.25)
a = z + 1 + alpha - math.floor(alpha / 4)
else:
a = z
b = a + 1524
c = math.floor((b - 122.1) / 365.25)
d = math.floor(365.25 * c)
e = math.floor((b - d) / 30.6001)
day = b - d - math.floor(30.6001 * e) + f
month = 0
year = 0
if e > 13:
month = e - 13
else:
month = e - 1
if month > 2:
year = c - 4716
else:
year = c - 4715
return year, month, round(day, self.ROUNDING_PLACES)
[docs]
def gregorian_date_from_jd_1(self, jd, alt=False):
"""
My algorithm
"""
# Get the number of days since the Gregorian epoch.
md = jd - (self.GREGORIAN_EPOCH - 1)
year = math.floor(abs(md / self.MEAN_TROPICAL_YEAR)) + 1
year *= -1 if md < (self.GREGORIAN_EPOCH - 1) else 1
# A refined number of days since epoch for the date.
td = self._days_in_years(year, alt=alt)
days = md - td
while days > 365:
year += 1
td = self._days_in_years(year, alt=alt)
days = md - td
if days == 0:
days = 365 if year < 0 and year % 4 != 0 else 366
else:
year += 1
month_days = list(self.MONTHS)
leap = self._gc._is_leap_year(year, alt=options.alt_leap)
month_days[1] = 29 if leap else 28
d = day = 0
for month, ds in enumerate(month_days, start=1):
d += ds
if days > d: continue
day = math.ceil(days - (d - ds))
break
f = jd % 1
day += f - (1.5 if f > 0.5 else 0.5)
if day < 1:
print("TEST--day: {day:<8} month: {month:<2}", file=sys.stderr)
month -= 1
day += 28
return (year, month, round(day, 6))
[docs]
def _days_in_years(self, y, alt=False):
n_4 = y // 4
if alt:
n_128 = y // 128
n_leap_years = n_4 - n_128
else:
n_100 = y // 100
n_400 = y // 400
n_leap_years = n_4 - n_100 + n_400
a = y - n_leap_years # Non-leap years
b = y - a # Leap years
return a * 365 + b * 366
[docs]
def date_from_ymdhms(self, date: tuple) -> tuple:
"""
Convert (year, month, day, hour, minute, second) into a
(year, month, day.partial) date.
"""
#self._check_valid_gregorian_month_day(date)
t_len = len(date)
year = date[0]
month = date[1]
day = date[2]
hour = date[3] if t_len > 3 and date[3] is not None else 0
minute = date[4] if t_len > 4 and date[4] is not None else 0
second = date[5] if t_len > 5 and date[5] is not None else 0
day += round(self.HR(hour) + self.MN(minute) + self.SEC(second),
self.ROUNDING_PLACES)
return (year, month, day)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(
description=("Test Julian Period methods."))
parser.add_argument(
'-a', '--analyze', action='store_true', default=False, dest='analyze',
help=("Generate a list of Julian Period days for both Meeus and "
"my formulas."))
parser.add_argument(
'-1', '--analyze-1', action='store_true', default=False,
dest='analyze_1',
help=("Generate a list of Julian Period days for different start "
"and end year."))
parser.add_argument(
'-2', '--analyze-2', action='store_true', default=False,
dest='analyze_2',
help=("Check that any Gregorian date can be converted to a Julian "
"Period day and then back again to a Gregorian date correctly."))
parser.add_argument(
'-c', '--compare', type=int, default=None, dest='compare',
help=("Compare two algorithms for determining the leap year. "
"A value <= 0 processes dates from 1 to 3004"))
parser.add_argument(
'-k', '--consecutive', action='store_true', default=False,
dest='consecutive', help="Test for non consecutive days.")
parser.add_argument(
'-j', '--julian-day', action='store_true', default=False,
dest='julian_day', help=("Generate list of Julian days with sunset "
"data days."))
parser.add_argument(
'-A', '--alt-leap', action='store_true', default=False,
dest='alt_leap', help="Use the 4|128 rule instead of the 4|100|400 "
"rule.")
parser.add_argument(
'-S', '--start', type=int, default=None, dest='start',
help="Start year of sequence.")
parser.add_argument(
'-E', '--end', type=int, default=None, dest='end',
help="End year of sequence.")
parser.add_argument(
'-M', '--meeus', action='store_true', default=False,
dest='meeus', help="Use Meeus' algorithm.")
parser.add_argument(
'-J', '--julian', action='store_true', default=False,
dest='julian', help="Test for consecutive Julian Period days.")
parser.add_argument(
'-G', '--g-date', action='store_true', default=False, dest='g_date',
help=("Test for consecutive Gregorian dates."))
parser.add_argument(
'-D', '--debug', action='store_true', default=False, dest='debug',
help="Run in debug mode.")
options = parser.parse_args()
jpt = JulianPeriodTests()
ret = 0
if options.debug:
sys.stderr.write("DEBUG--options: {}\n".format(options))
if options.analyze: # -a
data = [f"{idx:>02} "
f"{str(date):<17} "
f"{str(leap):<6} "
#f"{jd0:<10} " # Meeus
#f"{str(gd0):<17} " # Meeus
f"{jd1:<10} " # Mine
f"{str(gd1):<17} " # Mine
#f"{jd1 - jd0:<4}"
for (
idx,
(date, # Initial Gregorian date
leap, # Is leap year
jd0, # Meeus
gd0, # Meeus
jd1, # Mine
gd1) # Mine
) in enumerate(jpt.analyze(options), start=1)]
print("ID "
"Start Date"
" Leap"
#" Meeus"
#" Meeus"
" Mine"
" Mine"
#" Diff"
)
[print(item) for item in data]
elif options.analyze_1: # -1
if options.start is None or options.end is None:
print("If option -1 is used, -S and -E must also be used.",
file=sys.stderr)
ret = 1
else:
data = [f"{str(date):<17} " # Initial Gregorian date
f"{str(leap):<6} " # Is leap year
f"{jd0:<10} " # Meeus
f"{str(gd0):<17} " # Meeus
f"{jd1:<10} " # Mine
f"{str(gd1):<17} " # Mine
f"{jd1 - jd0:<5}" # Mine - Meeus (diff)
for (date,
leap,
jd0,
gd0,
jd1,
gd1) in jpt.analyze_1(options)]
print("Start Date "
"Leap "
"Meeus "
"Meeus "
"Mine "
"Mine "
"Diff"
)
[print(item) for item in data]
elif options.analyze_2: # -2
if options.start is None or options.end is None:
print("If option -2 is used, -S and -E must also be used.",
file=sys.stderr)
ret = 1
else:
data = [f"{str(date):<16} " # Initial Gregorian date
f"{str(gd1):<16} " # Mine
f"{jd1:<10} " # Mine
f"{str(leap):<6} " # Is leap year
for (date,
gd1,
jd1,
leap) in jpt.analyze_2(options)]
print("Date "
"gd1 "
"jd1 "
"Leap "
)
[print(item) for item in data]
elif isinstance(options.compare, int): # -c
data = [
f"Year {year:>4} "
f"GLY_STD {gly_std:<1} "
f"GLY_ALT {gly_alt:<1}"
for year, gly_std, gly_alt in jpt.compare_leap_year_algorithms(
options.compare)]
[print(item) for item in data]
elif options.consecutive: # -k
if options.start is None or options.end is None:
print("If option -k is used, -S and -E must also be used.",
file=sys.stderr)
ret = 1
elif options.julian:
data = [f"date: {str(date):<12} "
f"d: {d:<9} "
f"jd: {jd:<9}"
for date, d, jd in jpt.consecutive_days(options)]
elif options.g_date:
data = [f"last_date: {str(last_date):<15} "
f"last_jd: {d:<9} "
f"item: {str(item):<15} "
f"jd: {jd:<9} "
f"date: {str(date):<15}"
for last_date, d, item, jd, date in jpt.consecutive_days(
options)]
else:
print("You must choose one of -[JG].", file=sys.stderr)
ret = 1
if ret == 0: [print(item) for item in data]
elif options.julian_day: # -j
if options.start is None or options.end is None:
print("If option -j is used, -S and -E must also be used.",
file=sys.stderr)
ret = 1
else:
data = [
f"{str(date):<23} "
f"{jdss:<14}"
for date, jdss in jpt.julian_day_with_ut_sunset(options)]
[print(item) for item in data]
else:
parser.print_help()
sys.exit(ret)