public void TestToUniversalTimeUTCNow() { var expected = DateTime.UtcNow; var actual = BsonUtils.ToUniversalTime(expected.ToLocalTime()); Assert.AreEqual(expected, actual); }
public void TestToUniversalTimeMax() { var expected = DateTime.MaxValue; var actual = BsonUtils.ToUniversalTime(expected); Assert.AreEqual(expected, actual); }
/// <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); } }
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); }
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); }
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); }
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(); } }
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); } } }
// 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); } }
/// <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); } } }
// 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); }