[PYTHON] Conversion between Julian day and Gregorian calendar date

Hello. I calculated the conversion between the Gregorian calendar date $ (year, month, day) $ and the modified Julian day (MJD) or Julian day number (JDN). The flow of conversion calculation is as follows. For the calculation formula, see [Julian Day #Conversion from the Christian era] on Wikipedia (https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%AA%E3%82%A6%E3%] 82% B9% E9% 80% 9A% E6% 97% A5 # .E8.A5.BF.E6.9A.A6.E3.81.8B.E3.82.89.E3.81.AE.E6.8F.9B. E7.AE.97) (Julian day #Calculation) As it is [^ 1] [^ 2] [^ 3].

[^ 1]: Also, the difference between Gregorian and Julian calendars of this DELTA_N_MJD is that the matching period of both calendars is 100 years from March 1, 200 AD. Coming (not the first year of the Christian era), this comes from the Nikea Religious Council in 325 AD, which set the vernal equinox day on March 21st. [^ 2]: This value is because Masako UT ( `jd = 2400000.5```) on November 17, 1858 is the epoch of MJD ( `1858.680356 * 365.25 = 678883.000```). [^ 3]: In addition, although it appears in the calculation part of $ (y, m, d) \ leftrightarrow n $, the average number of days per month is 30.6 (= 153/5) days, and the number of days for 4 years is 1461 days. , The number of days for 400 years of the Gregorian calendar is 146097 days.

(year, month, day) \leftrightarrow (y, m, d) \leftrightarrow n \leftrightarrow mjd  \leftrightarrow jdn
$ ./date.py --test
True: ymd2n(0,0,0) == 0
True: date2ymd(0,3,1) == (0,0,0)
True: date2mjd(1858, 11, 17) == 0

date.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import division
from __future__ import print_function

# n: the continuous count of days since March first in 1 B.C. proleptic Gregorian
# date = (year, month, day) in the proleptic Gregorian calendar
# ymd  = (y, m, d); modified date in the proleptic Gregorian calendar (see date2ymd() below)

DELTA_N_MJD = {"Julian": 678883, "Gregorian": 678881}  # calendars

def mjd2jdn(mjd):
    return mjd + 2400001

def jdn2jd(jdn):
    return jdn - 0.5  # 00:00:00

def n2mjd(n):
    return n - DELTA_N_MJD["Gregorian"]

def mjd2n(mjd):
    return mjd + DELTA_N_MJD["Gregorian"]

def date2mjd(year, month, day):
    return n2mjd(date2n(year, month, day))

def mjd2date(mjd):
    return ymd2date(*n2ymd(mjd2n(mjd)))

def diffdate(date1, date2):
    return date2n(*date1) - date2n(*date2)

def adddate(date, d):
    n = date2n(*date) + d
    return ymd2date(n2ymd(n))

def date2n(year, month, day):
    return ymd2n(*date2ymd(year, month, day))

def date2ymd(year, month, day):
    y, m, d = year, month-3, day-1
    if m < 0:
        y, m = y-1, m%12
    return y, m, d

def ymd2date(y,m,d):
    year, month, day = y, m+3, d+1
    if month > 12:
        year, month = year+1, month%12
    return year, month, day

def ymd2n(y,m,d):
    n = d + (153*m+2)//5 + 365*y + y//4  # d + (306*m+4)//10 + (1461*y)//4
    n += -(y//100) + y//400  # (-3*(y//100))//4  [Gregorian]
    return n

def n2ymd(n):
    a = 4*n + 3
    a += 4*((3*((4*(n+1))//146097+1))//4)  # [Gregorian]
    y, b = a//1461, 5*((a%1461)//4) + 2
    m, d = b//153, (b%153)//5
    return y, m, d

def n2dayofweek(n):
   dow = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
   return dow[(n+3)%7]  # [Gregorian]

#===== test =====
def test_eval(str):
    print(eval(str), str)
    return 0
    
def test_epoch():
    test_eval('ymd2n(0,0,0) == 0')
    test_eval('date2ymd(0,3,1) == (0,0,0)')
    test_eval('date2mjd(1858, 11, 17) == 0')
    return 0

def test_ymd2n():
    for n in range(-146097,146097):
        y,m,d = n2ymd(n)
        if n != ymd2n(y,m,d):
            year, month, day = ymd2date(y,m,d)
            print(n,'', year, month, day, 'error')
            break
    return 0

def test_n2ymd():
    m, d = 0, 0
    for y in range(-401,400):
        n = ymd2n(y,m,d)
        if (y,m,d) != n2ymd(n):
            year, month, day = ymd2date(y,m,d)
            print(n,'', year, month, day, 'error')
            break
    return 0

def main():
    """
    {f}: Conversion between modified Julian day number and Gregorian calendar date.

    usage: {f} [-h] [--test]
    
    options:
        -h, --help    show this help message and exit
        --test        test
    """
    import docopt, textwrap
    args = docopt.docopt(textwrap.dedent(main.__doc__.format(f=__file__)))
    if args.get("--test", 0):
        test_epoch()
        test_ymd2n()
        test_n2ymd()
    return 0

if __name__ == '__main__':
    main()

Recommended Posts

Conversion between Julian day and Gregorian calendar date
Correct Gregorian calendar date from Julian day
Mutual conversion between date and days elapsed from January 1, 2000
Conversion between unixtime and datetime
Conversion between singular and plural of words
Mutual conversion between Qiita articles and Jupyter notebook
[Python] Conversion memo between time data and numerical data
Method to convert between Western calendar and Japanese calendar
Mutual conversion between fixed point and binary numbers
Mutual conversion between JSON and YAML / TOML in Python