edub
edub

Reputation: 689

Calculating julian date in python

I'm trying to create a julian date in python and having major struggles. Is there nothing out there as simple as:

jul = juliandate(year,month,day,hour,minute,second)

where jul would be something like 2457152.0 (the decimal changing with the time)?

I've tried jdcal, but can't figure out how to add the time component (jdcal.gcal2jd() only accepts year, month and day).

Upvotes: 6

Views: 34479

Answers (6)

Koosul
Koosul

Reputation: 46

The easiest: df['Julian_Dates']= df.index.to_julian_date(). you need to set your date time column to index (Use Pandas).

There is a way with using Astropy. First, change your time to a list (t). Second, change that list to astropy time (Time). Finally, compute your JD or MJD (t.jd t.mjd).
https://docs.astropy.org/en/stable/time/

For df: t = Time(DF.JulianDates,format='jd',scale='utc')

Upvotes: 2

SmittySmee
SmittySmee

Reputation: 400

Here you go - a pure python solution with datetime and math library.

This is based on the the Navy's Astronomical Equation found here and verified with their own calculator: http://aa.usno.navy.mil/faq/docs/JD_Formula.php

import datetime
import math

def get_julian_datetime(date):
    """
    Convert a datetime object into julian float.
    Args:
        date: datetime-object of date in question

    Returns: float - Julian calculated datetime.
    Raises: 
        TypeError : Incorrect parameter type
        ValueError: Date out of range of equation
    """

    # Ensure correct format
    if not isinstance(date, datetime.datetime):
        raise TypeError('Invalid type for parameter "date" - expecting datetime')
    elif date.year < 1801 or date.year > 2099:
        raise ValueError('Datetime must be between year 1801 and 2099')

    # Perform the calculation
    julian_datetime = 367 * date.year - int((7 * (date.year + int((date.month + 9) / 12.0))) / 4.0) + int(
        (275 * date.month) / 9.0) + date.day + 1721013.5 + (
                          date.hour + date.minute / 60.0 + date.second / math.pow(60,
                                                                                  2)) / 24.0 - 0.5 * math.copysign(
        1, 100 * date.year + date.month - 190002.5) + 0.5

    return julian_datetime

Usage Example:

# Set the same example as the Naval site.
example_datetime = datetime.datetime(1877, 8, 11, 7, 30, 0)
print get_julian_datetime(example_datetime)

Upvotes: 6

Janos Hajagos
Janos Hajagos

Reputation: 61

Not a pure Python solution but you can use the SQLite in memory db which has a julianday() function:

import sqlite3
con = sqlite3.connect(":memory:")
list(con.execute("select julianday('2017-01-01')"))[0][0]

which returns: 2457754.5

Upvotes: 6

Douglas G. Allen
Douglas G. Allen

Reputation: 2261

A simple fudge the numbers script via wiki don't know either. Please note that this was written using Python 3.6 so I'm not sure it would work on Python 2.7 but this is also an old question.

def julian_day(now):
    """
    1. Get current values for year, month, and day
    2. Same for time and make it a day fraction
    3. Calculate the julian day number via   https://en.wikipedia.org/wiki/Julian_day
    4. Add the day fraction to the julian day number

    """
    year = now.year
    month = now.month
    day = now.day
    day_fraction = now.hour + now.minute / 60.0 + now.second / 3600.0 / 24.0

    # The value 'march_on' will be 1 for January and February, and 0 for other months.
    march_on = math.floor((14 - month) / 12)
    year = year + 4800 - march_on
    # And 'month' will be 0 for March and 11 for February. 0 - 11 months
    month = month + 12 * march_on - 3

    y_quarter = math.floor(year / 4)
    jdn = day + math.floor((month * 153 + 2) / 5) + 365 * year + y_quarter

    julian = year < 1582 or year == (1582 and month < 10) or (month == 10 and day < 15)
    if julian:
        reform = 32083 # might need adjusting so needs a test
    else:
        reform = math.floor(year / 100) + math.floor(year / 400) + 32030.1875 # fudged this

    return jdn - reform + day_fraction

Generally this was just to try for myself as the most common algorithm was giving me trouble. That works and if you search around for it and write your script using it as it comes in many languages. But this one has steps in the docs to try to keep it simple. The biggest decision is how often are you going to look for dates that are before Gregorian reform. That is why I never tested that yet but go ahead and play with it as it needs a lot of massaging. :-D At least I think is conforms to PEP8 even if it isn't up to best practices. Go ahead and pylint it.

You could just use source packages like PyEphem or whatever but you still would like to know what's going on with it so you could write your own tests. I'll link that PyEphem for you but there are lots of ready made packages that have Julian Day calculations.

Your best bet if you are doing lots of work with these types of numbers is to get a list of the constant ones such as J2000.

datetime.datetime(2000, 1, 1, 12, 0, 0, tzinfo=datetime.timezone.utc)

datetime.datetime.toordinal() + 1721425 - 0.5 # not tested

# or even
datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)

It's not so hard to figure these out if you get familiar with what datetime library does. Just for fun did you notice the PyEphem logo? I suspect it comes from something like this

One post that I saw seems to work but has no tests is jiffyclub

Now here is the more common way to calculate two values using a datetime object.

def jdn(dto):
"""
Given datetime object returns Julian Day Number
"""
year = dto.year
month = dto.month
day = dto.day

not_march = month < 3
if not_march:
    year -= 1
    month += 12

fr_y = math.floor(year / 100)
reform = 2 - fr_y + math.floor(fr_y / 4)
jjs = day + (
    math.floor(365.25 * (year + 4716)) + math.floor(30.6001 * (month + 1)) + reform - 1524)
if jjs < ITALY:
    jjs -= reform

return jjs
# end jdn

def ajd(dto):
"""
Given datetime object returns Astronomical Julian Day.
Day is from midnight 00:00:00+00:00 with day fractional
value added.
"""
jdd = jdn(dto)
day_fraction = dto.hour / 24.0 + dto.minute / 1440.0 + dto.second / 86400.0
return jdd + day_fraction - 0.5
# end ajd

It may not be the best practice in Python but you did ask how to calculate it not just get it or extract it although if that is what you want those questions have been answered as of late.

Upvotes: 1

Porterhaus
Porterhaus

Reputation: 1

Try https://www.egenix.com/products/python/mxBase/mxDateTime/

First construct a DateTime object via the syntax

DateTime(year,month=1,day=1,hour=0,minute=0,second=0.0)

Then you can use '.jdn' object method to get the value you are looking for.

Upvotes: 0

Robert Jacobs
Robert Jacobs

Reputation: 3360

Answer one from Extract day of year and Julian day from a string date in python. No libraries required. Answer two is a library from https://pypi.python.org/pypi/jdcal

Upvotes: 2

Related Questions