简体   繁体   中英

Wrong result converting MsgPack timestamp 64 fields to DateTime

I am trying to implement the MsgPack TimeStamp 64 type in C#. This is what the specification says:

timestamp 64 stores the number of seconds and nanoseconds that have elapsed since 1970-01-01 00:00:00 UTC
in 32-bit unsigned integers:
+--------+--------+--------+--------+--------+------|-+--------+--------+--------+--------+
|  0xd7  |   -1   | nanosec. in 30-bit unsigned int |   seconds in 34-bit unsigned int    |
+--------+--------+--------+--------+--------+------^-+--------+--------+--------+--------+

* Timestamp 64 format can represent a timestamp in [1970-01-01 00:00:00.000000000 UTC, 2514-05-30 01:53:04.000000000 UTC) range.
* In timestamp 64 and timestamp 96 formats, nanoseconds must not be larger than 999999999.

Note that the seconds field is thirty- four bits, not thirty-two. So the max value can be computed by shifting a 32-bit max value unsigned int left two bits and setting the now-cleared two least-significant bits.

I tried to verify this with the following C# code but got different results:

DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); // the zero starting point
long maxSecs = ((long)uint.MaxValue << 2) | 3; // 17179869183
long maxNanoSec = 999999999; // not uint.MaxValue
TimeSpan maxNanoSecSpan = new TimeSpan(maxNanoSec * 100); // 1 tick = 100 nanosec.
DateTime MaxFExt8 = epoch.AddSeconds(maxSecs).Add(maxNanoSecSpan); 
Console.WriteLine(string.Concat("Timestamp 64 : ", epoch.ToString("yyyy-MM-dd HH:mm:ss.fffffff"), " - ", MaxFExt8.ToString("yyyy-MM-dd HH:mm:ss.fffffff")));

The output is:

Timestamp 64: 1970-01-01 00:00:00.0000000 - 2514-05-30 04:39:42.9999900

That is 2 hours, 46 minutes and 39 seconds too many...

After opening an issue about the difference, others checked and found they got the same results as the specs. One using the MacOS builtin NSDate type, the other using ruby.

I figure there must be a bug in my 6 lines of code, but I have been staring at it too long...

PS Note that this is not the MsgPack implementation yet, I first need to get the this right before I can start verifying my real code with unit tests. Conversion between little-endian and big-endian stuff with those shifted bits will only add more confusion if the basis is already broken....

You are multiplying nanoseconds when you should be dividing: TimeSpan maxNanoSecSpan = new TimeSpan(maxNanoSec * 100); .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM