How to convert Python datetime dates to decimal/float years

from datetime import datetime as dt
import time

def toYearFraction(date):
    def sinceEpoch(date): # returns seconds since epoch
        return time.mktime(date.timetuple())
    s = sinceEpoch

    year = date.year
    startOfThisYear = dt(year=year, month=1, day=1)
    startOfNextYear = dt(year=year+1, month=1, day=1)

    yearElapsed = s(date) - s(startOfThisYear)
    yearDuration = s(startOfNextYear) - s(startOfThisYear)
    fraction = yearElapsed/yearDuration

    return date.year + fraction

Demo:

>>> toYearFraction(dt.today())
2011.47447514

This method is probably accurate to within the second (or the hour if daylight savings or other strange regional things are in effect). It also works correctly during leapyears. If you need drastic resolution (such as due to changes in the Earth's rotation) you are better off querying a net service.


After implementing the accepted solution, I had the revelation that this modern pandas version is identical, and much simpler:

dat['decimal_date']=dat.index.year+ (dat.index.dayofyear -1)/365

Must be used on a date-time index Pandas dataframe. Adding as this solution post comes up in the top of my google search for this issue.


This is a little simpler way than the other solutions:

import datetime
def year_fraction(date):
    start = datetime.date(date.year, 1, 1).toordinal()
    year_length = datetime.date(date.year+1, 1, 1).toordinal() - start
    return date.year + float(date.toordinal() - start) / year_length

>>> print year_fraction(datetime.datetime.today())
2016.32513661

Note that this calculates the fraction based on the start of the day, so December 31 will be 0.997, not 1.0.