Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# DateTime AddDays Unexpected Offset

Tags:

c#

datetime

I have a very simple DateTime object that is set to the date 01-01-0001. I am supplied a value to add to this DateTime, in days. I am seeing an unexpected offset in my results though, of two days. Let's pretend I print out the results of the AddDays() call, like so:

DateTime myDateTime = DateTime.Parse("01-01-0001 00:00:00");
Console.WriteLine(myDateTime.AddDays(735768.0));

With the value seen above (735768.0) I expect an output of "6/18/2015 12:00:00 AM". However, instead I get "6/20/2015 12:00:00 AM". When I go to the following website and calculate the duration in days between 01-01-0001-->06/18/2015 I get a value of 735,768 days, as expected:

http://www.timeanddate.com/date/durationresult.html?m1=01&d1=01&y1=0001&m2=06&d2=18&y2=2015

Am I doing something wrong, or is there something going on under the hood that I am not aware of?

In case you are wondering, the 735,768 represents the first time value of the data that I am working with. The data is expected to start at 06/18/2015 00:00:00.

Edit: I should note I merely provided that particular website as an example of a conflicting source. Other websites, including the government weather agency I get the data from all give me 06-18-2015. This doesn't mean C# is wrong. I am more so curious as to where this offset came from, and why.

like image 612
Eric Bernier Avatar asked Jun 25 '15 17:06

Eric Bernier


2 Answers

Timeanddate.com is taking into account the calendar change from Julian to Gregorian, which explains the discrepancy.

You can actually see this change occur if you look at the difference between 01/01/1752 and 01/01/1753 on timeanddate.com:

Dates and times. They're crazy!

  • The formula for leap years on the Julian Calendar is "every year divisible by 4". This means that there are way more leap years in timeanddate.com's calculation between year 1 and year 1752, when the Calendar changes. This puts .NET's calculations until 1753 behind by 11 days.
  • Until 1752, England and the east coast of the United States used the Julian Calendar. A consequence of this change is that 1752 was only 355 days long. This calculation is not taken into account by .NET's calculation, and so at this point, .NET's calculation is two days ahead.

According to this answer by Jon Skeet, DateTime essentially uses the Gregorian calendar exclusively. This is why the above subtleties aren't reflected in .NET's calculations.

like image 176
Andrew Whitaker Avatar answered Nov 01 '22 22:11

Andrew Whitaker


.NET is giving you the "correct" answer - noting that "correct" is assuming a purely gregorian calendar as Andrew Whitaker points out in the comments below and answer above. Andrew's answer is more correct.

A leap year can be defined as divisible by 4, but not divisible by 100 unless it is divisible by 400. Therefore, since 1/1/0001 following those rules, there have been 488 leap days.

Accounting for these leap days, there have been 735,598 days from 1/1/0001 through end of 2014. This leaves us to find day #170 of 2015, which is 6/20/2015 (31 + 28 + 31 + 30 + 31 + 20).

Also, this is not a rounding issue in .NET as some have suggested. Since DateTime.AddDays uses ticks, which are long data types as 64-bit signed ints, no overflows or rounding is occurring.

Ticks/day = 864BB (or 8.64 x 10^11)
Tick / (2,015 years) ~ 1.75 x 10^15
Max long = 9,223,372,036,854,775,807 (or 9.22 x 10^18)
like image 4
Jason W Avatar answered Nov 01 '22 21:11

Jason W