You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.2 KiB
141 lines
3.2 KiB
import datetime
|
|
from enum import Enum
|
|
from typing import Union
|
|
|
|
|
|
class Calendar(Enum):
|
|
GREGORIAN = 1
|
|
JULIAN = 2
|
|
|
|
|
|
def day_fraction_to_time(fraction: float) -> datetime.time:
|
|
s = fraction * (24 * 60 * 60)
|
|
h = int(s / (60 * 60))
|
|
s -= h * 60 * 60
|
|
m = int(s / 60)
|
|
s -= m * 60
|
|
s = int(s)
|
|
return datetime.time(h, m, s)
|
|
|
|
|
|
def julianday(
|
|
at: Union[datetime.datetime, datetime.date], calendar: Calendar = Calendar.GREGORIAN
|
|
) -> float:
|
|
"""Calculate the Julian Day (number) for the specified date/time
|
|
|
|
julian day numbers for dates are calculated for the start of the day
|
|
"""
|
|
|
|
def _time_to_seconds(t: datetime.time) -> int:
|
|
return int(t.hour * 3600 + t.minute * 60 + t.second)
|
|
|
|
year = at.year
|
|
month = at.month
|
|
day = at.day
|
|
day_fraction = 0
|
|
if isinstance(at, datetime.datetime):
|
|
t = _time_to_seconds(at.time())
|
|
day_fraction = t / (24 * 60 * 60)
|
|
else:
|
|
day_fraction = 0
|
|
|
|
if month <= 2:
|
|
year -= 1
|
|
month += 12
|
|
|
|
a = int(year / 100)
|
|
if calendar == Calendar.GREGORIAN:
|
|
b = 2 - a + int(a / 4)
|
|
else:
|
|
b = 0
|
|
jd = (
|
|
int(365.25 * (year + 4716))
|
|
+ int(30.6001 * (month + 1))
|
|
+ day
|
|
+ day_fraction
|
|
+ b
|
|
- 1524.5
|
|
)
|
|
|
|
return jd
|
|
|
|
|
|
def julianday_modified(at: datetime.datetime) -> float:
|
|
"""Calculate the Modified Julian Date number"""
|
|
|
|
year = at.year
|
|
month = at.month
|
|
day = at.day
|
|
|
|
a = 10000 * year + 100 * month + day
|
|
|
|
if year < 0:
|
|
year += 1
|
|
|
|
if month <= 2:
|
|
month += 12
|
|
year -= 1
|
|
|
|
if a <= 15821004.1:
|
|
b = -2 + (year + 4716) / 4 - 1179
|
|
else:
|
|
b = (year / 400) - (year / 100) + (year / 4)
|
|
|
|
a = 365 * year - 679004
|
|
mjd = a + b + int(30.6001 * (month + 1)) + day + at.hour / 24
|
|
return mjd
|
|
|
|
|
|
def julianday_to_datetime(jd: float) -> datetime.datetime:
|
|
"""Convert a Julian Day number to a datetime"""
|
|
jd += 0.5
|
|
z = int(jd)
|
|
f = jd - z
|
|
if z < 2299161:
|
|
a = z
|
|
else:
|
|
alpha = int((z - 1867216.25) / 36524.25)
|
|
a = z + 1 + alpha + int(alpha / 4.0)
|
|
|
|
b = a + 1524
|
|
c = int((b - 122.1) / 365.25)
|
|
d = int(365.25 * c)
|
|
e = int((b - d) / 30.6001)
|
|
|
|
d = b - d - int(30.6001 * e) + f
|
|
day = int(d)
|
|
t = d - day
|
|
total_seconds = t * (24 * 60 * 60)
|
|
hour = int(total_seconds / 3600)
|
|
total_seconds -= hour * 3600
|
|
minute = int(total_seconds / 60)
|
|
total_seconds -= minute * 60
|
|
seconds = int(total_seconds)
|
|
|
|
if e < 14:
|
|
month = e - 1
|
|
else:
|
|
month = e - 13
|
|
|
|
if month > 2:
|
|
year = c - 4716
|
|
else:
|
|
year = c - 4715
|
|
|
|
return datetime.datetime(year, month, day, hour, minute, seconds)
|
|
|
|
|
|
def julianday_to_juliancentury(julianday: float) -> float:
|
|
"""Convert a Julian Day number to a Julian Century"""
|
|
return (julianday - 2451545.0) / 36525.0
|
|
|
|
|
|
def juliancentury_to_julianday(juliancentury: float) -> float:
|
|
"""Convert a Julian Century number to a Julian Day"""
|
|
return (juliancentury * 36525.0) + 2451545.0
|
|
|
|
|
|
def julianday_2000(at: Union[datetime.datetime, datetime.date]) -> float:
|
|
"""Calculate the numer of Julian Days since Jan 1.5, 2000"""
|
|
return julianday(at) - 2451545.0
|