How to get BsonTimestamp to DateTime in C# with millisecond granularity?

If I have ClusterTime returned from the Change Streams (via the .net driver and using C#), I can get BsonTimestamp values like:

Timestamp1 = 1587672311
Increment1 = 1
BsonType1 = Timestamp
Value1 = 6819000652509741057
===> DateTime = 4/23/2020 8:05:11 PM (no milliseconds, only seconds granulariyt)

Timestamp2 = 1587672311
Increment2 = 3
BsonType2 = Timestamp
Value2 = 6819000652509741059
===> DateTime = 4/23/2020 8:05:11 PM (no milliseconds, only seconds granularity)

I can make a DateTime from the BsonTimestamp by doing:

    /// <summary>
    /// GetDateTimeFromBsonTimestamp
    /// Conversion from a BsonTimestamp into DateTime
    /// </summary>
    /// <param name="timestamp">input BsonTimestamp timestamp</param>
    /// <returns>compatible DateTime result</returns>
    public static DateTime GetDateTimeFromBsonTimestamp(BsonTimestamp timestamp)
    {
        var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        return unixEpoch.AddSeconds(timestamp.Timestamp);
    }

What I’m struggling with is that this is only second granularity when these two ClusterTime’s (BsonTimestamps) have Value data that shows much more granularity. Can I translate that granularity in my DateTime values? How can BsonTimestamp.Value be used to offer the greatest time granularity in a conversion to DateTime?

Please let me know if you have pointers - thanks!

Jeremy

PS - @wan - if you have a pointer here, I’m all ears! Thanks!

I ended up finding this:
https://jira.mongodb.org/browse/JAVA-634

It looks like the granularity of time is only seconds in BsonTimestamp - 8 bytes total, but 4 bytes are seconds and 4 bytes is otherwise occupied byt ‘count’? This didn’t completely make sense to me yet, but if the ‘Value’ of BsonTimestamp contains nothing more than some variant of a count of seconds, then BsonTimestamp can really only give seconds granularity.

Any more light on this subject? Can a BsonTimestamp actually hand out millisecond granularity?

Final answer that I’ve found is that ‘sub-second granularity’ is accomplished wit h an indexed count of ordered changes (an ‘ordinal’ or ‘increment’ within the second). This can’t be turned into time, but could be used to create sub-second (false) timestamps solely for the sake of ordering. If the increment is pulled out, it can be used downstream to disambiguate within the second, but there isn’t any greater time granularity than seconds in BsonTimestamp in a pure ‘actual time’ sense.

Hope that helps anyone other than me who comes across this :slightly_smiling_face:

Jeremy Buch

2 Likes

Hi Jeremy,

Timestamps are an internal BSON type used by replication. This type is effectively a BSON Date (which is based on unixtime) combined with a counter to uniquely identify multiple events within the same second.

As you have discovered, Timestamps are not intended as a more granular version of the BSON Date for general time tracking use.

Regards,
Stennie