How do I read a date in Excel format in Python?

Viewed 136797

How can I convert an Excel date (in a number format) to a proper date in Python?

14 Answers

You can use xlrd.

From its documentation, you can read that dates are always stored as numbers; however, you can use xldate_as_tuple to convert it to a python date.

Note: the version on the PyPI seems more up-to-date than the one available on xlrd's website.

Here's the bare-knuckle no-seat-belts use-at-own-risk version:

import datetime

def minimalist_xldate_as_datetime(xldate, datemode):
    # datemode: 0 for 1900-based, 1 for 1904-based
    return (
        datetime.datetime(1899, 12, 30)
        + datetime.timedelta(days=xldate + 1462 * datemode)
        )

After testing and a few days wait for feedback, I'll svn-commit the following whole new function in xlrd's xldate module ... note that it won't be available to the diehards still running Python 2.1 or 2.2.

##
# Convert an Excel number (presumed to represent a date, a datetime or a time) into
# a Python datetime.datetime
# @param xldate The Excel number
# @param datemode 0: 1900-based, 1: 1904-based.
# <br>WARNING: when using this function to
# interpret the contents of a workbook, you should pass in the Book.datemode
# attribute of that workbook. Whether
# the workbook has ever been anywhere near a Macintosh is irrelevant.
# @return a datetime.datetime object, to the nearest_second.
# <br>Special case: if 0.0 <= xldate < 1.0, it is assumed to represent a time;
# a datetime.time object will be returned.
# <br>Note: 1904-01-01 is not regarded as a valid date in the datemode 1 system; its "serial number"
# is zero.
# @throws XLDateNegative xldate < 0.00
# @throws XLDateAmbiguous The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0)
# @throws XLDateTooLarge Gregorian year 10000 or later
# @throws XLDateBadDatemode datemode arg is neither 0 nor 1
# @throws XLDateError Covers the 4 specific errors

def xldate_as_datetime(xldate, datemode):
    if datemode not in (0, 1):
        raise XLDateBadDatemode(datemode)
    if xldate == 0.00:
        return datetime.time(0, 0, 0)
    if xldate < 0.00:
        raise XLDateNegative(xldate)
    xldays = int(xldate)
    frac = xldate - xldays
    seconds = int(round(frac * 86400.0))
    assert 0 <= seconds <= 86400
    if seconds == 86400:
        seconds = 0
        xldays += 1
    if xldays >= _XLDAYS_TOO_LARGE[datemode]:
        raise XLDateTooLarge(xldate)

    if xldays == 0:
        # second = seconds % 60; minutes = seconds // 60
        minutes, second = divmod(seconds, 60)
        # minute = minutes % 60; hour    = minutes // 60
        hour, minute = divmod(minutes, 60)
        return datetime.time(hour, minute, second)

    if xldays < 61 and datemode == 0:
        raise XLDateAmbiguous(xldate)

    return (
        datetime.datetime.fromordinal(xldays + 693594 + 1462 * datemode)
        + datetime.timedelta(seconds=seconds)
        )

Since there's a chance that your excel files are coming from different computers/people; there's a chance that the formatting is messy; so be extra cautious.

I just imported data from 50 odd excels where the dates were entered in DD/MM/YYYY or DD-MM-YYYY, but most of the Excel files stored them as MM/DD/YYYY (Probably because the PCs were setup with en-us instead of en-gb or en-in).

Even more irritating was the fact that dates above 13/MM/YYYY were in DD/MM/YYYY format still. So there was variations within the Excel files.

The most reliable solution I figured out was to manually set the Date column on each excel file to to be Plain Text -- then use this code to parse it:

if date_str_from_excel:
    try:
        return datetime.strptime(date_str_from_excel, '%d/%m/%Y')
    except ValueError:
        print("Unable to parse date")

excel stores dates and times as a number representing the number of days since 1900-Jan-0, if you want to get the dates in date format using python, just subtract 2 days from the days column, as shown below:

Date = sheet.cell(1,0).value-2 //in python

at column 1 in my excel, i have my date and above command giving me date values minus 2 days, which is same as date present in my excel sheet

This is a revised version from @hounded. My code handles both date and time, something like 43705.591795706

    import math
    import datetime


    def xldate_to_datetime(xldatetime): #something like 43705.6158241088

      tempDate = datetime.datetime(1899, 12, 31)
      (days, portion) = math.modf(xldatetime)

      deltaDays = datetime.timedelta(days=days)
      #changing the variable name in the edit
      secs = int(24 * 60 * 60 * portion)
      detlaSeconds = datetime.timedelta(seconds=secs)
      TheTime = (tempDate + deltaDays + detlaSeconds )
      return TheTime.strftime("%Y-%m-%d %H:%M:%S")


xldate_to_datetime(43705.6158241088)
# 2019-08-29 14:46:47

If you have a datetime column in excel file. Then below code will fix it. I went through a lot of answers on StackOverflow and nothing fixed it. I thought file is corrupted.

from datetime import datetime
jsts = 1468629431.0
datetime.fromtimestamp(jsts) 
Related