You have a "one by one" error in the numbering of your day - due to an error in Lotus 1-2-3 that Excel and other spreadsheet programs have carefully maintained compatibility for over 30 years.
Initially, the 1st day was supposed to be January 1, 1900 (which, as you said, would make day 0 equal to December 31, 1899). But Lotus misinterpreted 1900 as a leap year, so the number of days for everything until March 1 of this year is too large. Using these numbers with a calendar that correctly records 1900 as a regular year, the first day becomes December 31, and the 0th day returns to the 30th. Thus, the era for date arithmetic in Lotus-based spreadsheets is Saturday, December 30, 1899. (Modern Excel and some other spreadsheets extend compatibility with Lotus errors far enough to continue marking this date as December 31st, agreeing that it was Saturday, but other Lotus-based tables do not, and Ruby, of course does not do this.)
Even if you take this error into account, your declared example is incorrect: lot day 40 396 is August 6, 2010, and not October 15. I have confirmed this correspondence in Excel, LibreOffice and Google sheets, all of which agree. You must have crossed examples somewhere.
Here is one way to do the conversion:
Time.utc(1899,12,30) + 40396.days
Alternatively, you can use another well-known correspondence. The zero point for Ruby (and POSIX systems in general) is the moment January 1, 1970 at midnight GMT. January 1, 1970 is the day of the lotus 25 569. Until you forget to do your calculations in UTC, you can also do this:
Time.at( (40396 - 25569).days ).utc
In any case, you probably want to declare a symbolic constant for the epoch date (either a Time object representing 1899-12-30, or a POSIX value of "day 0" 25,569).
You can replace these calls with .days with multiplication by 86,400 if you don't need active_support/core_ext/integer/time for anything else, and you don't want to download it just for that.