-
Type: Bug
-
Resolution: Fixed
-
Priority: Critical - P2
-
Affects Version/s: None
-
Component/s: Serialization
-
(copied to CRM)
-
Needed
-
The default serialization for DateTimeOffset persists two values: a local date time (in ticks) + the original timezone, preventing searching across timezones. Consider the example:
Document A has the timestamp '2020-01-10 10:00:00 +00:00' and document B has the timestamp '2020-01-10 11:00:00 +01:00'. In .NET, comparing both timestamps returns true, because even though their timezones are different, both are referring to the same point in time.
Now, if I persist both documents to MongoDB and later I search for these documents using the timestamp '2020-01-10 10:00:00 +00:00', only the first document will be returned. If I search for '2020-01-10 11:00:00 +01:00' then only the second document will be returned. This is not the expected behaviour, essentially the search only works on local times and it even disregards the timezone.
Someone else raised this issue before on CSHARP-2603, but it was dismissed as support and no follow up is recorded. I solved this problem in my codebase by rolling my own serializer, which serialized the DateTime part of the type as UtcTicks, essentially solving the problem.
public class UtcDateTimeOffsetSerializer : StructSerializerBase<DateTimeOffset> { // public methods /// <summary> /// Deserializes a value. /// </summary> /// <param name="context">The deserialization context.</param> /// <param name="args">The deserialization args.</param> /// <returns>A deserialized value.</returns> public override DateTimeOffset Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { var bsonReader = context.Reader; var bsonType = bsonReader.GetCurrentBsonType(); if (bsonType != BsonType.Array) throw CreateCannotDeserializeFromBsonTypeException(bsonType); bsonReader.ReadStartArray(); var ticks = bsonReader.ReadInt64(); var offset = TimeSpan.FromMinutes(bsonReader.ReadInt32()); bsonReader.ReadEndArray(); return new DateTimeOffset(ticks + offset.Ticks, offset); } /// <summary> /// Serializes a value. /// </summary> /// <param name="context">The serialization context.</param> /// <param name="args">The serialization args.</param> /// <param name="value">The object.</param> public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DateTimeOffset value) { var bsonWriter = context.Writer; bsonWriter.WriteStartArray(); bsonWriter.WriteInt64(value.UtcTicks); bsonWriter.WriteInt32((int) value.Offset.TotalMinutes); bsonWriter.WriteEndArray(); } }
Given that this format is essentially incompatible with existing data, I would suggest that the default representation is changed from Array to Document so the DateTime portion is recorded in UTC epoch milliseconds, which is at least searchable.
- is depended on by
-
CSHARP-5296 Ensure that LINQ and builder queries work with the new DateTimeOffset default
- Ready for Work
- mentioned in
-
Page Loading...