예제 #1
0
        public void TestToUniversalTimeUTCNow()
        {
            var expected = DateTime.UtcNow;
            var actual   = BsonUtils.ToUniversalTime(expected.ToLocalTime());

            Assert.AreEqual(expected, actual);
        }
예제 #2
0
        public void TestToUniversalTimeMax()
        {
            var expected = DateTime.MaxValue;
            var actual   = BsonUtils.ToUniversalTime(expected);

            Assert.AreEqual(expected, actual);
        }
예제 #3
0
        /// <summary>
        /// Serializes an object to a BsonWriter.
        /// </summary>
        /// <param name="bsonWriter">The BsonWriter.</param>
        /// <param name="nominalType">The nominal type.</param>
        /// <param name="value">The object.</param>
        /// <param name="options">The serialization options.</param>
        public override void Serialize(
            BsonWriter bsonWriter,
            Type nominalType,
            object value,
            IBsonSerializationOptions options)
        {
            var dateTime = (DateTimeOffset)value;
            var dateTimeSerializationOptions = EnsureSerializationOptions <DateTimeSerializationOptions>(options);

            DateTime utcDateTime;

            utcDateTime = BsonUtils.ToUniversalTime(dateTime.UtcDateTime);
            var millisecondsSinceEpoch = BsonUtils.ToMillisecondsSinceEpoch(utcDateTime);

            switch (dateTimeSerializationOptions.Representation)
            {
            case BsonType.DateTime:
                bsonWriter.WriteDateTime(millisecondsSinceEpoch);
                break;

            case BsonType.Document:
                bsonWriter.WriteStartDocument();
                bsonWriter.WriteDateTime("DateTimeUTC", millisecondsSinceEpoch);
                bsonWriter.WriteInt64("Ticks", utcDateTime.Ticks);
                bsonWriter.WriteEndDocument();
                break;

            case BsonType.Int64:
                bsonWriter.WriteInt64(utcDateTime.Ticks);
                break;

            case BsonType.String:
                if (dateTimeSerializationOptions.DateOnly)
                {
                    bsonWriter.WriteString(dateTime.ToString("yyyy-MM-dd"));
                }
                else
                {
                    // we're not using XmlConvert.ToString because of bugs in Mono
                    if (dateTime == DateTime.MinValue || dateTime == DateTime.MaxValue)
                    {
                        // serialize MinValue and MaxValue as Unspecified so we do NOT get the time zone offset
                        dateTime = DateTime.SpecifyKind(dateTime.UtcDateTime, DateTimeKind.Unspecified);
                    }
                    else if (dateTime.UtcDateTime.Kind == DateTimeKind.Unspecified)
                    {
                        // serialize Unspecified as Local se we get the time zone offset
                        dateTime = DateTime.SpecifyKind(dateTime.UtcDateTime, DateTimeKind.Local);
                    }
                    bsonWriter.WriteString(dateTime.ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"));
                }
                break;

            default:
                var message = string.Format("'{0}' is not a valid DateTimeOffset representation.", dateTimeSerializationOptions.Representation);
                throw new BsonSerializationException(message);
            }
        }
예제 #4
0
        private static int GetTimestampFromDateTime(DateTime timestamp)
        {
            var secondsSinceEpoch = (long)Math.Floor((BsonUtils.ToUniversalTime(timestamp) -
                                                      BsonConstants.UnixEpoch).TotalSeconds);

            if (secondsSinceEpoch < int.MinValue || secondsSinceEpoch > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException(nameof(timestamp));
            }
            return((int)secondsSinceEpoch);
        }
예제 #5
0
        public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DateTimeOffset value)
        {
            BsonWriter bsonWriter = (BsonWriter)context.Writer;

            var      dateTime = (DateTimeOffset)value;
            DateTime utcDateTime;

            utcDateTime = BsonUtils.ToUniversalTime(dateTime.UtcDateTime);
            var millisecondsSinceEpoch = BsonUtils.ToMillisecondsSinceEpoch(utcDateTime);

            bsonWriter.WriteDateTime(millisecondsSinceEpoch);
        }
예제 #6
0
        public override DateTime Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
        {
            var      bsonReader      = context.Reader;
            var      currentBsonType = bsonReader.GetCurrentBsonType();
            DateTime value;

            switch (currentBsonType)
            {
            case BsonType.Document:
                value = new DateTime();
                _helper.DeserializeMembers(context,
                                           (elementName, flag) =>
                {
                    if (flag != DATE_TIME_FLAG)
                    {
                        if (flag != TICKS_FLAG)
                        {
                            return;
                        }

                        value = new DateTime(_int64Serializer.Deserialize(context), DateTimeKind.Utc);
                    }
                    else
                    {
                        bsonReader.SkipValue();
                    }
                });
                break;

            default:
                throw CreateCannotDeserializeFromBsonTypeException(currentBsonType);
            }

            switch (Kind)
            {
            case DateTimeKind.Local:
                value = DateTime.SpecifyKind(BsonUtils.ToLocalTime(value), DateTimeKind.Local);
                break;

            case DateTimeKind.Unspecified:
                value = DateTime.SpecifyKind(value, DateTimeKind.Unspecified);
                break;

            case DateTimeKind.Utc:
                value = BsonUtils.ToUniversalTime(value);
                break;

            default:
                throw CreateCannotDeserializeFromBsonTypeException(currentBsonType);
            }

            return(value);
        }
예제 #7
0
 public override void Serialize(BsonSerializationContext ctx, BsonSerializationArgs args, Date date)
 {
     if (date == null)
     {
         ctx.Writer.WriteNull();
     }
     else
     {
         var dtUTC = BsonUtils.ToUniversalTime(date.DateTime);
         ctx.Writer.WriteStartDocument();
         ctx.Writer.WriteDateTime("DateTime", BsonUtils.ToMillisecondsSinceEpoch(dtUTC));
         ctx.Writer.WriteInt64("Ticks", dtUTC.Ticks);
         ctx.Writer.WriteEndDocument();
     }
 }
예제 #8
0
        public override DateTime?ReadAsDateTime()
        {
            if (!ReadSkippingComments())
            {
                ReplaceCurrentToken(Newtonsoft.Json.JsonToken.None);
                return(null);
            }

            string message;

            switch (_tokenType)
            {
            case Newtonsoft.Json.JsonToken.Date:
                return((DateTime)_value);

            case Newtonsoft.Json.JsonToken.EndArray:
            case Newtonsoft.Json.JsonToken.Null:
                return(null);

            case Newtonsoft.Json.JsonToken.String:
                var stringValue = (string)Value;
                if (string.IsNullOrEmpty(stringValue))
                {
                    ReplaceCurrentToken(Newtonsoft.Json.JsonToken.Null);
                    return(null);
                }

                // TODO: handle all the different ways Json.NET handles DateTimes and TimeZones
                DateTime dateTime;
                if (DateTime.TryParse(stringValue, Culture, DateTimeStyles.RoundtripKind, out dateTime))
                {
                    dateTime = BsonUtils.ToUniversalTime(dateTime);
                    SetCurrentToken(Newtonsoft.Json.JsonToken.Date, dateTime, _bsonValue);
                    return(dateTime);
                }
                message = string.Format("Could not convert string to DateTime: {0}.", stringValue);
                throw new Newtonsoft.Json.JsonReaderException(message);

            default:
                message = string.Format("Error reading date. Unexpected token: {0}.", _tokenType);
                throw new Newtonsoft.Json.JsonReaderException(message);
            }
        }
        /// <summary>
        /// Serializes a value.
        /// </summary>
        /// <param name="context">The serialization context.</param>
        /// <param name="value">The object.</param>
        public override void Serialize(BsonSerializationContext context, DateTime value)
        {
            var bsonWriter = context.Writer;

            DateTime utcDateTime;

            if (_dateOnly)
            {
                if (value.TimeOfDay != TimeSpan.Zero)
                {
                    throw new BsonSerializationException("TimeOfDay component is not zero.");
                }
                utcDateTime = DateTime.SpecifyKind(value, DateTimeKind.Utc); // not ToLocalTime
            }
            else
            {
                utcDateTime = BsonUtils.ToUniversalTime(value);
            }
            var millisecondsSinceEpoch = BsonUtils.ToMillisecondsSinceEpoch(utcDateTime);

            switch (_representation)
            {
            case BsonType.DateTime:
                bsonWriter.WriteDateTime(millisecondsSinceEpoch);
                break;

            case BsonType.Document:
                bsonWriter.WriteStartDocument();
                bsonWriter.WriteDateTime("DateTime", millisecondsSinceEpoch);
                bsonWriter.WriteInt64("Ticks", utcDateTime.Ticks);
                bsonWriter.WriteEndDocument();
                break;

            case BsonType.Int64:
                bsonWriter.WriteInt64(utcDateTime.Ticks);
                break;

            case BsonType.String:
                if (_dateOnly)
                {
                    bsonWriter.WriteString(value.ToString("yyyy-MM-dd"));
                }
                else
                {
                    // we're not using XmlConvert.ToString because of bugs in Mono
                    if (value == DateTime.MinValue || value == DateTime.MaxValue)
                    {
                        // serialize MinValue and MaxValue as Unspecified so we do NOT get the time zone offset
                        value = DateTime.SpecifyKind(value, DateTimeKind.Unspecified);
                    }
                    else if (value.Kind == DateTimeKind.Unspecified)
                    {
                        // serialize Unspecified as Local se we get the time zone offset
                        value = DateTime.SpecifyKind(value, DateTimeKind.Local);
                    }
                    bsonWriter.WriteString(value.ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"));
                }
                break;

            default:
                var message = string.Format("'{0}' is not a valid DateTime representation.", _representation);
                throw new BsonSerializationException(message);
            }
        }
        // public methods
        /// <summary>
        /// Deserializes a value.
        /// </summary>
        /// <param name="context">The deserialization context.</param>
        /// <returns>An object.</returns>
        public override DateTime Deserialize(BsonDeserializationContext context)
        {
            var      bsonReader = context.Reader;
            DateTime value;

            var bsonType = bsonReader.GetCurrentBsonType();

            switch (bsonType)
            {
            case BsonType.DateTime:
                // use an intermediate BsonDateTime so MinValue and MaxValue are handled correctly
                value = new BsonDateTime(bsonReader.ReadDateTime()).ToUniversalTime();
                break;

            case BsonType.Document:
                value = default(DateTime);
                _helper.DeserializeMembers(context, (elementName, flag) =>
                {
                    switch (flag)
                    {
                    case Flags.DateTime: bsonReader.SkipValue(); break;         // ignore value (use Ticks instead)

                    case Flags.Ticks: value = new DateTime(context.DeserializeWithChildContext(_int64Serializer), DateTimeKind.Utc); break;
                    }
                });
                break;

            case BsonType.Int64:
                value = DateTime.SpecifyKind(new DateTime(bsonReader.ReadInt64()), DateTimeKind.Utc);
                break;

            case BsonType.String:
                // note: we're not using XmlConvert because of bugs in Mono
                if (_dateOnly)
                {
                    value = DateTime.SpecifyKind(DateTime.ParseExact(bsonReader.ReadString(), "yyyy-MM-dd", null), DateTimeKind.Utc);
                }
                else
                {
                    var formats = new string[] { "yyyy-MM-ddK", "yyyy-MM-ddTHH:mm:ssK", "yyyy-MM-ddTHH:mm:ss.FFFFFFFK" };
                    value = DateTime.ParseExact(bsonReader.ReadString(), formats, null, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
                }
                break;

            default:
                throw CreateCannotDeserializeFromBsonTypeException(bsonType);
            }

            if (_dateOnly)
            {
                if (value.TimeOfDay != TimeSpan.Zero)
                {
                    throw new FileFormatException("TimeOfDay component for DateOnly DateTime value is not zero.");
                }
                value = DateTime.SpecifyKind(value, _kind); // not ToLocalTime or ToUniversalTime!
            }
            else
            {
                switch (_kind)
                {
                case DateTimeKind.Local:
                case DateTimeKind.Unspecified:
                    value = DateTime.SpecifyKind(BsonUtils.ToLocalTime(value), _kind);
                    break;

                case DateTimeKind.Utc:
                    value = BsonUtils.ToUniversalTime(value);
                    break;
                }
            }

            return(value);
        }
        /// <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, object value)
        {
            var bsonWriter = context.Writer;

            if (value == null)
            {
                bsonWriter.WriteNull();
            }
            else
            {
                var actualType = value.GetType();
                if (actualType == typeof(object))
                {
                    bsonWriter.WriteStartDocument();
                    bsonWriter.WriteEndDocument();
                }
                else
                {
                    // certain types can be written directly as BSON value
                    // if we're not at the top level document, or if we're using the JsonWriter
                    if (bsonWriter.State == BsonWriterState.Value || bsonWriter is JsonWriter)
                    {
                        switch (Type.GetTypeCode(actualType))
                        {
                        case TypeCode.Boolean:
                            bsonWriter.WriteBoolean((bool)value);
                            return;

                        case TypeCode.DateTime:
                            // TODO: is this right? will lose precision after round trip
                            var bsonDateTime = new BsonDateTime(BsonUtils.ToUniversalTime((DateTime)value));
                            bsonWriter.WriteDateTime(bsonDateTime.MillisecondsSinceEpoch);
                            return;

                        case TypeCode.Double:
                            bsonWriter.WriteDouble((double)value);
                            return;

                        case TypeCode.Int16:
                            // TODO: is this right? will change type to Int32 after round trip
                            bsonWriter.WriteInt32((short)value);
                            return;

                        case TypeCode.Int32:
                            bsonWriter.WriteInt32((int)value);
                            return;

                        case TypeCode.Int64:
                            bsonWriter.WriteInt64((long)value);
                            return;

                        case TypeCode.Object:
                            if (actualType == typeof(Guid))
                            {
                                var guid = (Guid)value;
                                var guidRepresentation = bsonWriter.Settings.GuidRepresentation;
                                var binaryData         = new BsonBinaryData(guid, guidRepresentation);
                                bsonWriter.WriteBinaryData(binaryData);
                                return;
                            }
                            if (actualType == typeof(ObjectId))
                            {
                                bsonWriter.WriteObjectId((ObjectId)value);
                                return;
                            }
                            break;

                        case TypeCode.String:
                            bsonWriter.WriteString((string)value);
                            return;
                        }
                    }

                    SerializeDiscriminatedValue(context, args, value, actualType);
                }
            }
        }
예제 #12
0
        // public methods
        /// <summary>
        /// Deserializes an object from a BsonReader.
        /// </summary>
        /// <param name="bsonReader">The BsonReader.</param>
        /// <param name="nominalType">The nominal type of the object.</param>
        /// <param name="actualType">The actual type of the object.</param>
        /// <param name="options">The serialization options.</param>
        /// <returns>An object.</returns>
        public override object Deserialize(
            BsonReader bsonReader,
            Type nominalType,
            Type actualType,
            IBsonSerializationOptions options)
        {
            VerifyTypes(nominalType, actualType, typeof(BsonDateTime));
            var dateTimeSerializationOptions = EnsureSerializationOptions <DateTimeSerializationOptions>(options);

            var bsonType = bsonReader.GetCurrentBsonType();

            if (bsonType == BsonType.Null)
            {
                bsonReader.ReadNull();
                return(null);
            }
            else
            {
                long?millisecondsSinceEpoch = null;
                long?ticks = null;
                switch (bsonType)
                {
                case BsonType.DateTime:
                    millisecondsSinceEpoch = bsonReader.ReadDateTime();
                    break;

                case BsonType.Document:
                    bsonReader.ReadStartDocument();
                    millisecondsSinceEpoch = bsonReader.ReadDateTime("DateTime");
                    bsonReader.ReadName("Ticks");
                    var ticksValue = BsonValue.ReadFrom(bsonReader);
                    if (!ticksValue.IsBsonUndefined)
                    {
                        ticks = ticksValue.ToInt64();
                    }
                    bsonReader.ReadEndDocument();
                    break;

                case BsonType.Int64:
                    ticks = bsonReader.ReadInt64();
                    break;

                case BsonType.String:
                    // note: we're not using XmlConvert because of bugs in Mono
                    DateTime dateTime;
                    if (dateTimeSerializationOptions.DateOnly)
                    {
                        dateTime = DateTime.SpecifyKind(DateTime.ParseExact(bsonReader.ReadString(), "yyyy-MM-dd", null), DateTimeKind.Utc);
                    }
                    else
                    {
                        var formats = new string[] { "yyyy-MM-ddK", "yyyy-MM-ddTHH:mm:ssK", "yyyy-MM-ddTHH:mm:ss.FFFFFFFK", };
                        dateTime = DateTime.ParseExact(bsonReader.ReadString(), formats, null, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
                    }
                    ticks = dateTime.Ticks;
                    break;

                default:
                    var message = string.Format("Cannot deserialize DateTime from BsonType {0}.", bsonType);
                    throw new FileFormatException(message);
                }

                BsonDateTime bsonDateTime;
                if (ticks.HasValue)
                {
                    bsonDateTime = BsonDateTime.Create(new DateTime(ticks.Value, DateTimeKind.Utc));
                }
                else
                {
                    bsonDateTime = BsonDateTime.Create(millisecondsSinceEpoch.Value);
                }

                if (dateTimeSerializationOptions.DateOnly)
                {
                    var dateTime = bsonDateTime.Value;
                    if (dateTime.TimeOfDay != TimeSpan.Zero)
                    {
                        throw new FileFormatException("TimeOfDay component for DateOnly DateTime value is not zero.");
                    }
                    bsonDateTime = BsonDateTime.Create(DateTime.SpecifyKind(dateTime, dateTimeSerializationOptions.Kind)); // not ToLocalTime or ToUniversalTime!
                }
                else
                {
                    if (bsonDateTime.IsValidDateTime)
                    {
                        var dateTime = bsonDateTime.Value;
                        switch (dateTimeSerializationOptions.Kind)
                        {
                        case DateTimeKind.Local:
                        case DateTimeKind.Unspecified:
                            dateTime = DateTime.SpecifyKind(BsonUtils.ToLocalTime(dateTime), dateTimeSerializationOptions.Kind);
                            break;

                        case DateTimeKind.Utc:
                            dateTime = BsonUtils.ToUniversalTime(dateTime);
                            break;
                        }
                        bsonDateTime = BsonDateTime.Create(dateTime);
                    }
                    else
                    {
                        if (dateTimeSerializationOptions.Kind != DateTimeKind.Utc)
                        {
                            throw new FileFormatException("BsonDateTime is outside the range of .NET DateTime.");
                        }
                    }
                }

                return(bsonDateTime);
            }
        }
예제 #13
0
        /// <summary>
        /// Serializes an object to a BsonWriter.
        /// </summary>
        /// <param name="bsonWriter">The BsonWriter.</param>
        /// <param name="nominalType">The nominal type.</param>
        /// <param name="value">The object.</param>
        /// <param name="options">The serialization options.</param>
        public override void Serialize(
            BsonWriter bsonWriter,
            Type nominalType,
            object value,
            IBsonSerializationOptions options)
        {
            if (value == null)
            {
                bsonWriter.WriteNull();
            }
            else
            {
                var bsonDateTime = (BsonDateTime)value;
                var dateTimeSerializationOptions = EnsureSerializationOptions <DateTimeSerializationOptions>(options);

                DateTime utcDateTime = DateTime.MinValue;
                long     millisecondsSinceEpoch;
                if (dateTimeSerializationOptions.DateOnly)
                {
                    if (bsonDateTime.Value.TimeOfDay != TimeSpan.Zero)
                    {
                        throw new BsonSerializationException("TimeOfDay component is not zero.");
                    }
                    utcDateTime            = DateTime.SpecifyKind(bsonDateTime.Value, DateTimeKind.Utc); // not ToLocalTime
                    millisecondsSinceEpoch = BsonUtils.ToMillisecondsSinceEpoch(utcDateTime);
                }
                else
                {
                    if (bsonDateTime.IsValidDateTime)
                    {
                        utcDateTime = BsonUtils.ToUniversalTime(bsonDateTime.Value);
                    }
                    millisecondsSinceEpoch = bsonDateTime.MillisecondsSinceEpoch;
                }

                switch (dateTimeSerializationOptions.Representation)
                {
                case BsonType.DateTime:
                    bsonWriter.WriteDateTime(millisecondsSinceEpoch);
                    break;

                case BsonType.Document:
                    bsonWriter.WriteStartDocument();
                    bsonWriter.WriteDateTime("DateTime", millisecondsSinceEpoch);
                    if (bsonDateTime.IsValidDateTime)
                    {
                        bsonWriter.WriteInt64("Ticks", utcDateTime.Ticks);
                    }
                    else
                    {
                        bsonWriter.WriteUndefined("Ticks");
                    }
                    bsonWriter.WriteEndDocument();
                    break;

                case BsonType.Int64:
                    if (bsonDateTime.IsValidDateTime)
                    {
                        bsonWriter.WriteInt64(utcDateTime.Ticks);
                    }
                    else
                    {
                        throw new BsonSerializationException("BsonDateTime is not a valid DateTime.");
                    }
                    break;

                case BsonType.String:
                    if (dateTimeSerializationOptions.DateOnly)
                    {
                        bsonWriter.WriteString(bsonDateTime.Value.ToString("yyyy-MM-dd"));
                    }
                    else
                    {
                        // we're not using XmlConvert.ToString because of bugs in Mono
                        var dateTime = bsonDateTime.Value;
                        if (dateTime == DateTime.MinValue || dateTime == DateTime.MaxValue)
                        {
                            // serialize MinValue and MaxValue as Unspecified so we do NOT get the time zone offset
                            dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
                        }
                        else if (dateTime.Kind == DateTimeKind.Unspecified)
                        {
                            // serialize Unspecified as Local se we get the time zone offset
                            dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
                        }
                        bsonWriter.WriteString(dateTime.ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"));
                    }
                    break;

                default:
                    var message = string.Format("'{0}' is not a valid DateTime representation.", dateTimeSerializationOptions.Representation);
                    throw new BsonSerializationException(message);
                }
            }
        }
예제 #14
0
        // public methods
        /// <summary>
        /// Deserializes an object from a BsonReader.
        /// </summary>
        /// <param name="bsonReader">The BsonReader.</param>
        /// <param name="nominalType">The nominal type of the object.</param>
        /// <param name="actualType">The actual type of the object.</param>
        /// <param name="options">The serialization options.</param>
        /// <returns>An object.</returns>
        public override object Deserialize(
            BsonReader bsonReader,
            Type nominalType,
            Type actualType,
            IBsonSerializationOptions options)
        {
            VerifyTypes(nominalType, actualType, typeof(DateTime));

            var      dateTimeOptions = (options == null) ? DateTimeSerializationOptions.Defaults : (DateTimeSerializationOptions)options;
            DateTime value;

            var bsonType = bsonReader.CurrentBsonType;

            switch (bsonType)
            {
            case BsonType.DateTime:
                // use an intermediate BsonDateTime so MinValue and MaxValue are handled correctly
                value = BsonDateTime.Create(bsonReader.ReadDateTime()).Value;
                break;

            case BsonType.Document:
                bsonReader.ReadStartDocument();
                bsonReader.ReadDateTime("DateTime");     // ignore value (use Ticks instead)
                value = new DateTime(bsonReader.ReadInt64("Ticks"), DateTimeKind.Utc);
                bsonReader.ReadEndDocument();
                break;

            case BsonType.Int64:
                value = DateTime.SpecifyKind(new DateTime(bsonReader.ReadInt64()), DateTimeKind.Utc);
                break;

            case BsonType.String:
                // note: we're not using XmlConvert because of bugs in Mono
                if (dateTimeOptions.DateOnly)
                {
                    value = DateTime.SpecifyKind(DateTime.ParseExact(bsonReader.ReadString(), "yyyy-MM-dd", null), DateTimeKind.Utc);
                }
                else
                {
                    var formats = new string[] { "yyyy-MM-ddK", "yyyy-MM-ddTHH:mm:ssK", "yyyy-MM-ddTHH:mm:ss.FFFFFFFK" };
                    value = DateTime.ParseExact(bsonReader.ReadString(), formats, null, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
                }
                break;

            default:
                var message = string.Format("Cannot deserialize DateTime from BsonType {0}.", bsonType);
                throw new FileFormatException(message);
            }

            if (dateTimeOptions.DateOnly)
            {
                if (value.TimeOfDay != TimeSpan.Zero)
                {
                    throw new FileFormatException("TimeOfDay component for DateOnly DateTime value is not zero.");
                }
                value = DateTime.SpecifyKind(value, dateTimeOptions.Kind); // not ToLocalTime or ToUniversalTime!
            }
            else
            {
                switch (dateTimeOptions.Kind)
                {
                case DateTimeKind.Local:
                case DateTimeKind.Unspecified:
                    value = DateTime.SpecifyKind(BsonUtils.ToLocalTime(value), dateTimeOptions.Kind);
                    break;

                case DateTimeKind.Utc:
                    value = BsonUtils.ToUniversalTime(value);
                    break;
                }
            }

            return(value);
        }