Click here to Skip to main content
15,915,065 members
Articles / Programming Languages / C++

Excel Serial Date to Day, Month, Year and Vice Versa

Rate me:
Please Sign up or sign in to vote.
4.96/5 (18 votes)
12 Aug 2002CDDL2 min read 412.2K   31   38
A speedy algorithm to convert Excel numbers to DMY and vice versa

Introduction

For a little project of mine, I needed to convert a serial date number to day/month/year (DMY) and vice versa. The serial number came from date field in a converted Paradox database and seemed to be exactly the same as the serial date in Microsoft Excel, hence the article name. After some Googling, I learned that the Excel serial date is related to Julian date, and found a speedy algorithm to convert these numbers to DMY and vice versa.

Excel Serial Date Number

Now what is an Excel serial date number? 37477 is a serial date number and is the number of days since 1-1-1900. 37477 actually translates to Aug 9, 2002, the date of writing this article.

The number of days since 1-1-1900 isn't that hard to calculate of course, once you know the leap years. Microsoft Excel however contains a bug with its date calculation: it considers 29-02-1900 as a valid date, but 1900 isn't a leap year! 29-02-1900 is not a valid date!

According to the stories, Microsoft decided to duplicate this date bug from Lotus 123, which was the dominating spreadsheet application at the time Excel was being written. This allowed Excel to open Lotus 123 spreadsheets without date problems.

(Note that a serial date number may also contain a fraction that denotes the time. It's actually the percentage of 24 hours, but that's not for this article.)

Mac Excel Serial Date number

Excel on the Apple Mac uses a slightly different Serial Date number base: the number of days since 1-1-1904. That's why Excel also features a "1904 Date System" checkbox in its Options (Calculation tab). I won't go into this further.

Translating Serial Date Number to DMY

First of all, credit where credit is due. I got the basic algorithm from here. It's about converting a Julian date to DMY using integer calculations. I won't bore you with the theory (following the above hyperlink), but the original Julian has a different base date.

With an addition of a certain number, the algorithm comes close to the Excel serial date. And when the 29-02-1900 issue is handled, we've got an Excel serial date to Day, Month, Year calculation!

C++
void ExcelSerialDateToDMY(int nSerialDate, int &nDay, 
                          int &nMonth, int &nYear)
{
    // Excel/Lotus 123 have a bug with 29-02-1900. 1900 is not a
    // leap year, but Excel/Lotus 123 think it is...
    if (nSerialDate == 60)
    {
        nDay    = 29;
        nMonth    = 2;
        nYear    = 1900;

        return;
    }
    else if (nSerialDate < 60)
    {
        // Because of the 29-02-1900 bug, any serial date 
        // under 60 is one off... Compensate.
        nSerialDate++;
    }

    // Modified Julian to DMY calculation with an addition of 2415019
    int l = nSerialDate + 68569 + 2415019;
    int n = int(( 4 * l ) / 146097);
            l = l - int(( 146097 * n + 3 ) / 4);
    int i = int(( 4000 * ( l + 1 ) ) / 1461001);
        l = l - int(( 1461 * i ) / 4) + 31;
    int j = int(( 80 * l ) / 2447);
     nDay = l - int(( 2447 * j ) / 80);
        l = int(j / 11);
        nMonth = j + 2 - ( 12 * l );
    nYear = 100 * ( n - 49 ) + i + l;
}

DMY to Excel Serial Date

Calculate an Excel serial date from Day, Month, Year. The function assumes that the day, month and year are valid date numbers.

C++
int DMYToExcelSerialDate(int nDay, int nMonth, int nYear)
{
    // Excel/Lotus 123 have a bug with 29-02-1900. 1900 is not a
    // leap year, but Excel/Lotus 123 think it is...
    if (nDay == 29 && nMonth == 02 && nYear==1900)
        return 60;

    // DMY to Modified Julian calculated with an extra subtraction of 2415019.
    long nSerialDate = 
            int(( 1461 * ( nYear + 4800 + int(( nMonth - 14 ) / 12) ) ) / 4) +
            int(( 367 * ( nMonth - 2 - 12 * ( ( nMonth - 14 ) / 12 ) ) ) / 12) -
            int(( 3 * ( int(( nYear + 4900 + int(( nMonth - 14 ) / 12) ) / 100) ) ) / 4) +
            nDay - 2415019 - 32075;

    if (nSerialDate < 60)
    {
        // Because of the 29-02-1900 bug, any serial date 
        // under 60 is one off... Compensate.
        nSerialDate--;
    }

    return (int)nSerialDate;
}

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


Written By
Software Developer (Senior)
Netherlands Netherlands
Victor is consulting in The Netherlands.

His interests include Windows and web application development using .NET technologies and even some Apache/PHP/MySQL...

Comments and Discussions

 
GeneralExcel dates in C# Pin
Kris Vandermotten3-Apr-03 1:30
Kris Vandermotten3-Apr-03 1:30 
GeneralRe: Excel dates in C# Pin
Victor Vogelpoel3-Apr-03 7:41
Victor Vogelpoel3-Apr-03 7:41 
GeneralRe: Excel dates in C# Pin
VentsyV29-Nov-07 12:39
VentsyV29-Nov-07 12:39 
GeneralThanks! Just what I needed Pin
Timian Heber12-Nov-02 8:58
Timian Heber12-Nov-02 8:58 
GeneralRe: Thanks! Just what I needed Pin
Victor Vogelpoel12-Nov-02 9:21
Victor Vogelpoel12-Nov-02 9:21 
GeneralISO 8601 (International Standard Date Format) Pin
Warren Stevens13-Aug-02 2:46
Warren Stevens13-Aug-02 2:46 
GeneralRe: ISO 8601 (International Standard Date Format) Pin
Victor Vogelpoel13-Aug-02 3:08
Victor Vogelpoel13-Aug-02 3:08 
GeneralRe: ISO 8601 (International Standard Date Format) Pin
Warren Stevens13-Aug-02 3:54
Warren Stevens13-Aug-02 3:54 
Victor,

Victor Vogelpoel wrote:
I'm disappointed that you haven't even read the article and specifically the code

I read your entire article, including all of the code in the article. Your article is titled "Excel serial date to DMY and vise versa" (i.e. converting between two representations of date), so I don't think a comment on the international standard for date format qualifies as "out of the blue".

Victor Vogelpoel wrote:
The code uses three seperate variables nDay, nMonth and nYear and converts an Excel Serial Date number like 37481 to day 13, month 8, year 2002 and vise vera. NOWHERE is a DMY order enforced. You're welcome to create a ISO Standard date STRING from these numbers using sprintf(szBuff, "%d-%d-%d", nYear, nMonth, nDay) or any format for that matter...

I realized that. Changing the format from DMY to YMD doesn't change the code you've presented at all, but that wasn't my point. I added the comment because you mention "DMY" a lot in your article (e.g. the title), and I wanted to point out that there is an international standard for dates, seeing as this website is visited by people from all around the world.

Victor Vogelpoel wrote:
everybody all over the world will recognize DMY as being a Day/Month/Year

There are reasons to justify using all kinds of different formats (DMY, YMD, MDY, etc), but as long as multiple formats are used around the world, there will be confusion. There is already an international standard, so why not use it?

If you want to use DMY as your format, I'm not going to be able to convince you to do otherwise. I just wanted to point out that there is an international standard for dates, in case some other reader of your article might be interested.

Warren
GeneralRe: ISO 8601 (International Standard Date Format) Pin
Victor Vogelpoel13-Aug-02 4:18
Victor Vogelpoel13-Aug-02 4:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.