DateTimeOffsetSerializer.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /* Copyright 2010-present MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.IO;
  17. using MongoDB.Bson.IO;
  18. using MongoDB.Bson.Serialization.Attributes;
  19. using MongoDB.Bson.Serialization.Options;
  20. namespace MongoDB.Bson.Serialization.Serializers
  21. {
  22. /// <summary>
  23. /// Represents a serializer for DateTimeOffsets.
  24. /// </summary>
  25. public class DateTimeOffsetSerializer : StructSerializerBase<DateTimeOffset>, IRepresentationConfigurable<DateTimeOffsetSerializer>
  26. {
  27. // private constants
  28. private static class Flags
  29. {
  30. public const long DateTime = 1;
  31. public const long Ticks = 2;
  32. public const long Offset = 4;
  33. }
  34. // private fields
  35. private readonly SerializerHelper _helper;
  36. private readonly Int32Serializer _int32Serializer = new Int32Serializer();
  37. private readonly Int64Serializer _int64Serializer = new Int64Serializer();
  38. private readonly BsonType _representation;
  39. // constructors
  40. /// <summary>
  41. /// Initializes a new instance of the <see cref="DateTimeOffsetSerializer"/> class.
  42. /// </summary>
  43. public DateTimeOffsetSerializer()
  44. : this(BsonType.Array)
  45. {
  46. }
  47. /// <summary>
  48. /// Initializes a new instance of the <see cref="DateTimeOffsetSerializer"/> class.
  49. /// </summary>
  50. /// <param name="representation">The representation.</param>
  51. public DateTimeOffsetSerializer(BsonType representation)
  52. {
  53. switch (representation)
  54. {
  55. case BsonType.Array:
  56. case BsonType.Document:
  57. case BsonType.String:
  58. break;
  59. default:
  60. var message = string.Format("{0} is not a valid representation for a DateTimeOffsetSerializer.", representation);
  61. throw new ArgumentException(message);
  62. }
  63. _representation = representation;
  64. _helper = new SerializerHelper
  65. (
  66. new SerializerHelper.Member("DateTime", Flags.DateTime),
  67. new SerializerHelper.Member("Ticks", Flags.Ticks),
  68. new SerializerHelper.Member("Offset", Flags.Offset)
  69. );
  70. }
  71. // public properties
  72. /// <summary>
  73. /// Gets the representation.
  74. /// </summary>
  75. /// <value>
  76. /// The representation.
  77. /// </value>
  78. public BsonType Representation
  79. {
  80. get { return _representation; }
  81. }
  82. // public methods
  83. /// <summary>
  84. /// Deserializes a value.
  85. /// </summary>
  86. /// <param name="context">The deserialization context.</param>
  87. /// <param name="args">The deserialization args.</param>
  88. /// <returns>A deserialized value.</returns>
  89. public override DateTimeOffset Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
  90. {
  91. var bsonReader = context.Reader;
  92. long ticks;
  93. TimeSpan offset;
  94. BsonType bsonType = bsonReader.GetCurrentBsonType();
  95. switch (bsonType)
  96. {
  97. case BsonType.Array:
  98. bsonReader.ReadStartArray();
  99. ticks = bsonReader.ReadInt64();
  100. offset = TimeSpan.FromMinutes(bsonReader.ReadInt32());
  101. bsonReader.ReadEndArray();
  102. return new DateTimeOffset(ticks, offset);
  103. case BsonType.Document:
  104. ticks = 0;
  105. offset = TimeSpan.Zero;
  106. _helper.DeserializeMembers(context, (elementName, flag) =>
  107. {
  108. switch (flag)
  109. {
  110. case Flags.DateTime: bsonReader.SkipValue(); break; // ignore value
  111. case Flags.Ticks: ticks = _int64Serializer.Deserialize(context); break;
  112. case Flags.Offset: offset = TimeSpan.FromMinutes(_int32Serializer.Deserialize(context)); break;
  113. }
  114. });
  115. return new DateTimeOffset(ticks, offset);
  116. case BsonType.String:
  117. return JsonConvert.ToDateTimeOffset(bsonReader.ReadString());
  118. default:
  119. throw CreateCannotDeserializeFromBsonTypeException(bsonType);
  120. }
  121. }
  122. /// <summary>
  123. /// Serializes a value.
  124. /// </summary>
  125. /// <param name="context">The serialization context.</param>
  126. /// <param name="args">The serialization args.</param>
  127. /// <param name="value">The object.</param>
  128. public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DateTimeOffset value)
  129. {
  130. var bsonWriter = context.Writer;
  131. // note: the DateTime portion cannot be serialized as a BsonType.DateTime because it is NOT in UTC
  132. switch (_representation)
  133. {
  134. case BsonType.Array:
  135. bsonWriter.WriteStartArray();
  136. bsonWriter.WriteInt64(value.Ticks);
  137. bsonWriter.WriteInt32((int)value.Offset.TotalMinutes);
  138. bsonWriter.WriteEndArray();
  139. break;
  140. case BsonType.Document:
  141. bsonWriter.WriteStartDocument();
  142. bsonWriter.WriteDateTime("DateTime", BsonUtils.ToMillisecondsSinceEpoch(value.UtcDateTime));
  143. bsonWriter.WriteInt64("Ticks", value.Ticks);
  144. bsonWriter.WriteInt32("Offset", (int)value.Offset.TotalMinutes);
  145. bsonWriter.WriteEndDocument();
  146. break;
  147. case BsonType.String:
  148. bsonWriter.WriteString(JsonConvert.ToString(value));
  149. break;
  150. default:
  151. var message = string.Format("'{0}' is not a valid DateTimeOffset representation.", _representation);
  152. throw new BsonSerializationException(message);
  153. }
  154. }
  155. /// <summary>
  156. /// Returns a serializer that has been reconfigured with the specified representation.
  157. /// </summary>
  158. /// <param name="representation">The representation.</param>
  159. /// <returns>The reconfigured serializer.</returns>
  160. public DateTimeOffsetSerializer WithRepresentation(BsonType representation)
  161. {
  162. if (representation == _representation)
  163. {
  164. return this;
  165. }
  166. else
  167. {
  168. return new DateTimeOffsetSerializer(representation);
  169. }
  170. }
  171. // explicit interface implementations
  172. IBsonSerializer IRepresentationConfigurable.WithRepresentation(BsonType representation)
  173. {
  174. return WithRepresentation(representation);
  175. }
  176. }
  177. }