2

Is datetime values with microseconds are converted into double with exact precision?

For eg. i have date as 3 July 2017 10:00:00 00 Ticks 636346728000000050. which converted into double as i am getting as 42919.4166666667. As similarly, i have added the 50 Ticks to current date ie. 3 July 2017 10:00:00 00 Ticks 636346728000000100 which converted into double, also getting same double value but the ticks value has added into date.

I am converted into double by this method date.ToOADate()

can anyone please resolve this ?

Thanks in advance :)

Parthiban
  • 168
  • 1
  • 13
  • 1
    There is no such thing as "exact precision" in measuring time. – vijoc Jul 03 '17 at 06:59
  • Why are you converting it into a double? – Magnus Jul 03 '17 at 07:08
  • in my requirement, i have convert into double for some operations. – Parthiban Jul 03 '17 at 07:11
  • "i have added the 50 Ticks" - How? DateTime is immutable. Much more is unclear here, so write a [mcve]. – H H Jul 03 '17 at 07:19
  • Double is a floating-point value which means it is an approximation of the calculated value. So if you need this kind of resolution you should use the Ticks value (long) instead. – Magnus Jul 03 '17 at 07:21
  • The time part of an OLE automation date is just the fraction into the day. There is not enough precision in an double to express the 5 milliseconds you are trying to add. – Palle Due Jul 03 '17 at 07:25
  • @PalleDue - the double should be able to cope, depending on the zeropoint a little. – H H Jul 03 '17 at 07:29
  • @PalleDue yes. but is there any way to add ? – Parthiban Jul 03 '17 at 07:30
  • @Parthiban: I did the same exercise as you. I created a DateTime, July 3rd 10 o'clock, created another one 50 ticks later, converted both to OADate and they were both exactly the same. As Henk points out precision is dependent on the zero-point as precision is higher around zero and lower near the "ends", but it looks like it's not good enough for this. – Palle Due Jul 03 '17 at 07:51

3 Answers3

4

50 ticks cannot be expressed in a OLE Automation date. This code:

DateTime d1 = DateTime.Parse("3 July 2017 10:00:00");
DateTime d2 = d1.AddTicks(100);
double o2 = d2.ToOADate();
Console.WriteLine(o2);

DateTime d3 = d1.AddTicks(1000);
double o3 = d3.ToOADate();
Console.WriteLine(o3);

DateTime d4 = d1.AddTicks(10000); 
double o4 = d4.ToOADate();
Console.WriteLine(o4);

generates the output:

42919,4166666667
42919,4166666667
42919,4166666782

so you need at least 10000 ticks for the add to have an impact.

Palle Due
  • 5,929
  • 4
  • 17
  • 32
  • In my answer I assumed that using ToOADate was a requirement. Rereading the question, I see that the question doesn't explicitly say, it just talks about converting a datetime to double. – Palle Due Jul 03 '17 at 08:37
  • Thanks for your efforts. yes. i just need to convert the datetime to double. as you said, only 10000 ticks(1 ms) have an impact. my question is there is any other way to convert with by adding microseconds date? – Parthiban Jul 03 '17 at 08:50
3

There are two separate logical operations here:

  • Converting from ticks to microseconds. This is basically a matter of dividing by 10 (there are 100 nanoseconds or 0.1 microseconds in each tick), so that can lose information already in integer arithmetic - but adding 50 ticks is adding exactly 5 microseconds, so that should be okay.

  • Converting from an integer to a binary floating point number. Your value has 17 significant decimal digits, which is on the higher end of what a 64-bit binary floating point type can represent. You shouldn't rely on more than 15 significant decimal digits.

On top of that, you're using ToOADate, which appears to have millisecond precision, looking at the reference source.

So:

  • You could just divide Ticks by 10 to get microseconds, only losing a small amount of precision
  • You could convert from long to double in a different way, which would lose less information than ToOADate but you're still going to be losing information in many cases.
  • If you divide by 10.0 (so avoiding the integer arithmetic to start with) then depending on the value you're trying to represent, you could avoid losing any information.

If you are able to choose a different epoch for your double value, you could easily express microseconds in values with appropriate precision - but you'd need to know the range of values you need to express in order to check that, as well as having control over the rest of the code using the resulting double values.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
0

The conversion function ToOADate does not support such small differences. 50 ticks are 50*100ns = 5 μs.

If you check other functions like SystemTimeToVariantTime or VariantTimeToSystemTime, you will find that they are even more restricted, to 1 second precision.

https://www.codeproject.com/Articles/17576/SystemTime-to-VariantTime-with-Milliseconds provides code to allow millisecond precision.

The current resolution for the OLE date is around 629ns, the difference between two doubles with day count (integer part) around 44057 (like today), so everything below 7 Ticks will not make a difference.

One option to calculate an improved OLE date is to convert your ODate back to DateTime, then correct the Ole date based on the Tick difference:

DateTime now = DateTime.Now;
double olenow = now.ToOADate();
DateTime oanow = DateTime.FromOADate(olenow);
double betterolenow = olenow + ((double)(now.Ticks - oanow.Ticks) ) / (24L * 3600 * 1000 * 10000);