Excel stores dates as a number of days since January 0, 1900 (with a famous bug that treats 1900 as a leap year). This converter handles both directions: paste an Excel serial number to get a date, or paste a date to get the Excel value.
Microsoft Excel stores dates as serial numbers representing the count of days since January 0, 1900 (a day that doesn't actually exist — Excel uses it as a reference origin). The format is called OADate (OLE Automation Date) and is also used by Microsoft Access, Visual Basic, and various COM/OLE APIs.
Common situations where you'll encounter Excel serial numbers:
Double values=NOW() in an unformatted cell)Excel mistakenly treats 1900 as a leap year (it isn't — years divisible by 100 but not 400 are not leap years). This was inherited from Lotus 1-2-3 for backwards compatibility and has been preserved in every Excel version since 1985. The effect:
For practical purposes (any modern date), use the formula (serial - 25569) × 86400 to convert to Unix seconds. The bug only affects dates in Jan–Feb 1900.
unix_seconds = (excel_serial - 25569) * 86400
The 25569 is the number of days from Excel's epoch (1900-01-00) to Unix's epoch (1970-01-01), accounting for the leap-year bug.
excel_serial = (unix_seconds / 86400) + 25569
Older versions of Excel for Mac used a different epoch: 1904-01-01. The offset is (1904-01-01 to 1970-01-01) = 24107 days. If you get a workbook with dates that look off by 4 years and a day, it was probably created in 1904-mode Excel. This converter uses the standard 1900 system; for 1904 mode, subtract 1462 from any serial value first.
const EXCEL_OFFSET_DAYS = 25569;
const SECONDS_PER_DAY = 86400;
function excelToDate(serial) {
const unixSec = (serial - EXCEL_OFFSET_DAYS) * SECONDS_PER_DAY;
return new Date(unixSec * 1000);
}
function dateToExcel(date) {
return (date.getTime() / 1000 / SECONDS_PER_DAY) + EXCEL_OFFSET_DAYS;
}
from datetime import datetime, timezone, timedelta
EXCEL_EPOCH = datetime(1899, 12, 30, tzinfo=timezone.utc)
def excel_to_datetime(serial: float) -> datetime:
return EXCEL_EPOCH + timedelta(days=serial)
def datetime_to_excel(dt: datetime) -> float:
return (dt - EXCEL_EPOCH).total_seconds() / 86400
// Convert Unix seconds in cell A1 to a date in Excel
=(A1 / 86400) + 25569
// Then format the cell as Date/Time