I have a string "2012.11.07"
in python. I need to convert it to date object and then get an integer value of day of year and also Julian day. Is it possible?
-
2It's not called Julian Day if you just want the day number for the year. https://en.wikipedia.org/wiki/Ordinal_date – Douglas G. Allen Jan 20 '17 at 18:50
10 Answers
First, you can convert it to a datetime.datetime
object like this:
>>> import datetime
>>> fmt = '%Y.%m.%d'
>>> s = '2012.11.07'
>>> dt = datetime.datetime.strptime(s, fmt)
>>> dt
datetime.datetime(2012, 11, 7, 0, 0)
Then you can use the methods on datetime
to get what you want… except that datetime
doesn't have the function you want directly, so you need to convert to a time tuple
>>> tt = dt.timetuple()
>>> tt.tm_yday
312
The term "Julian day" has a few different meanings. If you're looking for 2012312
, you have to do that indirectly, e.g., one of the following.
>>> int('%d%03d' % (tt.tm_year, tt.tm_yday))
2012312
>>> tt.tm_year * 1000 + tt.tm_yday
2012312
If you're looking for a different meaning, you should be able to figure it out from here. For example, if you want the "days since 1 Jan 4713 BC" meaning, and you have a formula that requires Gregorian year and day in year, you've got those two values above to plug in. (If you have a formula that takes Gregorian year, month, and day, you don't even need the timetuple
step.) If you can't work out where to go from there, ask for further details.
If you don't have a formula—and maybe even if you already do—your best bet is probably to look around PyPI and ActiveState for pre-existing modules. For example, a quick search turned up something called jdcal
. I'd never seen it before, but a quick pip install jdcal
and a brief skim of the readme, and I was able to do this:
>>> sum(jdcal.gcal2jd(dt.year, dt.month, dt.day))
2456238.5
That's the same result that the USN Julian date converter gave me.
If you want integral Julian day, instead of fractional Julian date, you have to decide which direction you want to round—toward 0, toward negative infinity, rounding noon up to the next day, rounding noon toward even days, etc. (Note that Julian date is defined as starting since noon on 1 Jan 4713BC, so half of 7 Nov 2012 is 2456238, the other half is 2456239, and only you know which one of those you want…) For example, to round toward 0:
>>> int(sum(jdcal.gcal2jd(dt.year, dt.month, dt.day)))
2456238

- 354,177
- 51
- 601
- 671
-
[julian *day* is an integer number](http://stackoverflow.com/a/25831416/4279). gcal2jd() returns julian *date*. – jfs Sep 14 '14 at 08:26
-
1@J.F.Sebastian: Read the linked docs. "Julian dates are stored in two floating point numbers (double)." `jdcal` is returning fractional Julian days (assuming noon if given only a date). If you want to argue that these shouldn't be called Julian days but something else, take it up with the author of the module. – abarnert Sep 15 '14 at 18:01
-
it is your responsibility to make sure that the module *you* suggested returns what OP asks. – jfs Sep 15 '14 at 18:04
-
1@J.F.Sebastian: Fine, I've added the code to call `int`. But the point isn't to give the OP code that he can use without thinking, or to recommend a specific library; I used `gdcal` as an example of the kinds of libraries you can find with a quick google, PyPI, or ActiveState search; it's still up to the OP to do that search, evaluate the libraries, and pick the one he wants. – abarnert Sep 15 '14 at 18:44
-
it might be better to assume noon given a date instead of midnight of the previous day i.e., it should be 39 as in [my answer](http://stackoverflow.com/a/25831416/4279), not 38. Your point is valid but wouldn't it be nicer to provide the research results in the answer if possible to avoid forcing people to duplicate it. – jfs Sep 15 '14 at 19:37
-
@J.F.Sebastian: The research results were literally "search `PyPI julian`, click the first line, skim its readme, `pip install jdcal`, run one of the examples from the readme, verify that it looks reasonable." As for rounding up… OK, I'll put that in the answer too. – abarnert Sep 15 '14 at 19:41
-
pico-nitpick: Julian day number is an integer. Julian date is inherently fractional: [*"The Julian Date (JD) of any instant is the Julian day number for the preceding noon plus the fraction of the day since that instant."*](http://www.iers.org/nn_10910/IERS/EN/Science/Recommendations/resolutionB1.html) – jfs Sep 16 '14 at 01:56
-
the issue with the "light" research approach is that calendar computations can be deceptively simple. If you don't care about nuances that can be ignored in most situations then you could use the explicit formula as in my answer. Possible errors are exposed that way. I understand that most questions for most people do not require a well-researched answer. – jfs Sep 16 '14 at 01:59
-
@J.F.Sebastian: OK, so I'm not clear on what you're disagreeing with. There is no unique Julian day corresponding to a particular date—instead, there's half of one Julian day, and half of another. Which one is the "right" one depends on what the application is trying to do. And when you're starting with just a date string, the answer to that question is equivalent to the question of how to round a Julian date to a Julian day for your application, right? Does my last paragraph not convey that clearly enough? If not, what should I change? – abarnert Sep 16 '14 at 17:37
-
To get the Julian day, use the datetime.date.toordinal
method and add a fixed offset.
The Julian day is the number of days since January 1, 4713 BC at 12:00 in the proleptic Julian calendar, or November 24, 4714 BC at 12:00 in the proleptic Gregorian calendar. Note that each Julian day starts at noon, not midnight.
The toordinal
function returns the number of days since December 31, 1 BC at 00:00 in the proleptic Gregorian calendar (in other words, January 1, 1 AD at 00:00 is the start of day 1, not day 0). Note that 1 BC directly precedes 1 AD, there was no year 0 since the number zero wasn't invented until many centuries later.
import datetime
datetime.date(1,1,1).toordinal()
# 1
Simply add 1721424.5 to the result of toordinal
to get the Julian day.
Another answer already explained how to parse the string you started with and turn it into a datetime.date
object. So you can find the Julian day as follows:
import datetime
my_date = datetime.date(2012,11,7) # time = 00:00:00
my_date.toordinal() + 1721424.5
# 2456238.5

- 815
- 8
- 7
To simplify the initial steps of abarnert's answer:
from dateutil import parser
s = '2012.11.07'
dt = parser.parse(s)
then apply the rest of abanert's answer.

- 5,465
- 6
- 44
- 56
-
which version of python is this? tm_yday is not there for me @ 2.7 – Curtis Price Jun 12 '13 at 18:53
-
it is for me. Did you forget to convert to a timetuple? the dt object does not have a member tm_yday, while the time.struct_time object that you get from dt.timetuple() has that member. – K.-Michael Aye Jun 12 '13 at 23:03
For quick computations, you could find day of year and Julian day number using only stdlib datetime
module:
#!/usr/bin/env python3
from datetime import datetime, timedelta
DAY = timedelta(1)
JULIAN_EPOCH = datetime(2000, 1, 1, 12) # noon (the epoch name is unrelated)
J2000_JD = timedelta(2451545) # julian epoch in julian dates
dt = datetime.strptime("2012.11.07", "%Y.%m.%d") # get datetime object
day_of_year = (dt - datetime(dt.year, 1, 1)) // DAY + 1 # Jan the 1st is day 1
julian_day = (dt.replace(hour=12) - JULIAN_EPOCH + J2000_JD) // DAY
print(day_of_year, julian_day)
# 312 2456239
Another way to get day_of_year
:
import time
day_of_year = time.strptime("2012.11.07", "%Y.%m.%d").tm_yday
julian_day
in the code above is "the Julian day number associated with the solar day -- the number assigned to a day in a continuous count of days beginning with the Julian day number 0 assigned to the day starting at Greenwich mean noon on 1 January 4713 BC, Julian proleptic calendar -4712".
The time
module documentation uses the term "Julian day" differently:
Jn
The Julian day n (1 <= n <= 365). Leap days are not counted, so in all years February 28 is day 59 and March 1 is day 60.
n
The zero-based Julian day (0 <= n <= 365). Leap days are counted, and it is possible to refer to February 29.
i.e., the zero-based Julian day is day_of_year - 1
here. And the first one (Jn
) is day_of_year - (calendar.isleap(dt.year) and day_of_year > 60)
-- the days starting with March 1 are shifted to exclude the leap day.
There is also a related term: Julian date. Julian day number is an integer. Julian date is inherently fractional: "The Julian Date (JD) of any instant is the Julian day number for the preceding noon plus the fraction of the day since that instant."
In general, to avoid handling edge cases yourself, use a library to compute Julian day as suggested by @abarnert.
This functionality (conversion of date strings to Julian date/time) is also present in the astropy module. Please refer to their documentation for complete details. The astropy implementation is especially handy for easy conversions to Julian time, as opposed to just the Julian date.
Example solution for the original question:
>>> import astropy.time
>>> import dateutil.parser
>>> dt = dateutil.parser.parse('2012.11.07')
>>> time = astropy.time.Time(dt)
>>> time.jd
2456238.5
>>> int(time.jd)
2456238

- 322
- 2
- 7
I import datetime lib, and use strftime to extract 'julian day', year, month, day...
import datetime as dt
my_date = dt.datetime.strptime('2012.11.07', '%Y.%m.%d')
jld_str = my_date.strftime('%j') # '312'
jld_int = int(jld_str) # 312

- 153
- 1
- 2
- 6
According to this article there is an unpublished one-line formula created by Fliegel and Van Flandern to calculate an Gregorian Date to an Julian Date:
JD = 367 * year - 7 * (year + (month + 9)/12)/4 - 3 * ((year + (month - 9)/7)/100 + 1)/4 + 275 * month/9 + day + 1721029
This was compacted by P. M. Muller and R. N. Wimberly of the Jet Propulsion Laboratory, Pasadena, California for dates after March of 1900 to:
JD = 367 * year - 7 * (year + (month + 9)/12)/4 + 275 * month/9 + day + 1721014
These formulas are off by 0.5, so just subtract 0.5 from the formulas.
Use some string manupulation to actually extract the data and you will be good
>>> year, month, day = map(int,"2018.11.02".split("."))
>>> 367 * year - 7 * (year + (month + 9)/12)/4 + 275 * month/9 + day + 1721014 - 0.5
2458424.5

- 21
- 3
-
One important point about these calculations is that they presume Fortran semantics for integer division, in particular, the article says "In the above formulae, division by integers implies truncation of the quotients to integers." Copying this formula to Python, as you do in your example, will be generally incorrect as Python rounds towards -infinity for integer division. For example, the first formula will yield 2415417 both for 31 January 1901 and also for 1 February 1901, which is clearly incorrect. – reddish Apr 08 '22 at 07:22
-
Second comment is that the first formula is only correct for positive year numbers. Year 1 BCE was followed by 1 CE, and there is no "year 0". For BCE years (i.e., year < 0), you need to add 1 to the year first. – reddish Apr 08 '22 at 08:04
From the above examples, here is the one liner (non-Julian):
import datetime
doy = datetime.datetime.strptime('2014-01-01', '%Y-%m-%d').timetuple().tm_yday

- 2,995
- 28
- 16
def JulianDate_to_date(y, jd):
month = 1
while jd - calendar.monthrange(y,month)[1] > 0 and month <= 12:
jd = jd - calendar.monthrange(y,month)[1]
month += 1
date = datetime.date(y,month,jd).strftime("%m/%d/%Y")
return date

- 117
- 7
While the answer of @FGol provides self-contained formulae, it should be noted that those formulae are only valid if division rounds towards zero (so-called "truncated division"), which is language-dependent.
Python, for example, implements rounding towards -infinity, which is quite different. To use the formulae given in Python, you can do something like this:
def trunc_div(a, b):
"""Implement 'truncated division' in Python."""
return (a // b) if a >= 0 else -(-a // b)
def formula1(year, month, day):
"""Convert Gregorian date to julian day number."""
return 367 * year - trunc_div(7 * (year + trunc_div(month + 9, 12)), 4) - trunc_div(3 * (trunc_div(year + trunc_div(month - 9, 7), 100) + 1), 4) + trunc_div(275 * month, 9) + day + 1721029
def formula2(year, month, day):
"""Convert Gregorian date to julian day number (simplified); only valid for dates from March 1900 and beyond."""
return 367 * year - trunc_div(7 * (year + trunc_div(month + 9, 12)), 4) + trunc_div(275 * month, 9) + day + 1721014

- 1,360
- 2
- 12
- 27