1515
1616using System ;
1717using MongoDB . Bson . IO ;
18+ using MongoDB . Bson . Serialization . Attributes ;
1819using MongoDB . Bson . Serialization . Options ;
1920
2021namespace MongoDB . Bson . Serialization . Serializers
@@ -26,7 +27,7 @@ namespace MongoDB.Bson.Serialization.Serializers
2627 public sealed class DateOnlySerializer : StructSerializerBase < DateOnly > , IRepresentationConfigurable < DateOnlySerializer >
2728 {
2829 // static
29- private static readonly DateOnlySerializer __instance = new DateOnlySerializer ( ) ;
30+ private static readonly DateOnlySerializer __instance = new ( ) ;
3031
3132 /// <summary>
3233 /// Gets the default DateOnlySerializer.
@@ -38,19 +39,26 @@ private static class Flags
3839 {
3940 public const long DateTime = 1 ;
4041 public const long Ticks = 2 ;
42+ public const long Year = 4 ;
43+ public const long Month = 8 ;
44+ public const long Day = 16 ;
45+
46+ public const long DateTimeTicks = DateTime | Ticks ;
47+ public const long YearMonthDay = Year | Month | Day ;
4148 }
4249
4350 // private fields
4451 private readonly RepresentationConverter _converter ;
4552 private readonly SerializerHelper _helper ;
4653 private readonly BsonType _representation ;
54+ private readonly DateOnlyDocumentFormat _documentFormat ;
4755
4856 // constructors
4957 /// <summary>
5058 /// Initializes a new instance of the <see cref="DateOnlySerializer"/> class.
5159 /// </summary>
5260 public DateOnlySerializer ( )
53- : this ( BsonType . DateTime )
61+ : this ( BsonType . DateTime , DateOnlyDocumentFormat . DateTimeTicks )
5462 {
5563 }
5664
@@ -59,6 +67,16 @@ public DateOnlySerializer()
5967 /// </summary>
6068 /// <param name="representation">The representation.</param>
6169 public DateOnlySerializer ( BsonType representation )
70+ : this ( representation , DateOnlyDocumentFormat . DateTimeTicks )
71+ {
72+ }
73+
74+ /// <summary>
75+ /// Initializes a new instance of the <see cref="DateOnlySerializer"/> class.
76+ /// </summary>
77+ /// <param name="representation">The representation.</param>
78+ /// <param name="documentFormat">The format to use with the BsonType.Document representation. It will be ignored if the representation is different.</param>
79+ public DateOnlySerializer ( BsonType representation , DateOnlyDocumentFormat documentFormat )
6280 {
6381 switch ( representation )
6482 {
@@ -73,73 +91,84 @@ public DateOnlySerializer(BsonType representation)
7391 }
7492
7593 _representation = representation ;
94+ _documentFormat = documentFormat ;
7695 _converter = new RepresentationConverter ( false , false ) ;
77-
7896 _helper = new SerializerHelper
7997 (
80- new SerializerHelper . Member ( "DateTime" , Flags . DateTime ) ,
81- new SerializerHelper . Member ( "Ticks" , Flags . Ticks )
98+ new SerializerHelper . Member ( "DateTime" , Flags . DateTime , isOptional : true ) ,
99+ new SerializerHelper . Member ( "Ticks" , Flags . Ticks , isOptional : true ) ,
100+ new SerializerHelper . Member ( "Year" , Flags . Year , isOptional : true ) ,
101+ new SerializerHelper . Member ( "Month" , Flags . Month , isOptional : true ) ,
102+ new SerializerHelper . Member ( "Day" , Flags . Day , isOptional : true )
82103 ) ;
83104 }
84105
85106 // public properties
86107 /// <inheritdoc />
87108 public BsonType Representation => _representation ;
88109
110+ /// <summary>
111+ /// The format to use for the BsonType.Document representation. It will be ignored if the representation is different.
112+ /// </summary>
113+ public DateOnlyDocumentFormat DocumentFormat => _documentFormat ;
114+
89115 //public methods
90116 /// <inheritdoc />
91117 public override DateOnly Deserialize ( BsonDeserializationContext context , BsonDeserializationArgs args )
92118 {
93119 var bsonReader = context . Reader ;
94- DateOnly value ;
95120
96121 var bsonType = bsonReader . GetCurrentBsonType ( ) ;
97122
98123 switch ( bsonType )
99124 {
100125 case BsonType . DateTime :
101- value = VerifyAndMakeDateOnly ( BsonUtils . ToDateTimeFromMillisecondsSinceEpoch ( bsonReader . ReadDateTime ( ) ) ) ;
102- break ;
126+ return VerifyAndMakeDateOnly ( BsonUtils . ToDateTimeFromMillisecondsSinceEpoch ( bsonReader . ReadDateTime ( ) ) ) ;
103127
104128 case BsonType . Document :
105- value = default ;
106- _helper . DeserializeMembers ( context , ( _ , flag ) =>
129+ var ticks = 0L ;
130+ var year = 0 ;
131+ var month = 0 ;
132+ var day = 0 ;
133+
134+ var foundMemberFlags = _helper . DeserializeMembers ( context , ( _ , flag ) =>
107135 {
108136 switch ( flag )
109137 {
110- case Flags . DateTime : bsonReader . SkipValue ( ) ; break ; // ignore value (use Ticks instead)
111- case Flags . Ticks :
112- value = VerifyAndMakeDateOnly ( new DateTime ( Int64Serializer . Instance . Deserialize ( context ) , DateTimeKind . Utc ) ) ;
113- break ;
138+ case Flags . DateTime : bsonReader . SkipValue ( ) ; break ; // ignore value (use Ticks instead)
139+ case Flags . Ticks : ticks = Int64Serializer . Instance . Deserialize ( context ) ; break ;
140+ case Flags . Year : year = Int32Serializer . Instance . Deserialize ( context ) ; break ;
141+ case Flags . Month : month = Int32Serializer . Instance . Deserialize ( context ) ; break ;
142+ case Flags . Day : day = Int32Serializer . Instance . Deserialize ( context ) ; break ;
114143 }
115144 } ) ;
116- break ;
145+
146+ return foundMemberFlags switch
147+ {
148+ Flags . DateTimeTicks => VerifyAndMakeDateOnly ( new DateTime ( ticks , DateTimeKind . Utc ) ) ,
149+ Flags . YearMonthDay => new DateOnly ( year , month , day ) ,
150+ _ => throw new FormatException ( "Invalid document format." )
151+ } ;
117152
118153 case BsonType . Decimal128 :
119- value = VerifyAndMakeDateOnly ( new DateTime ( _converter . ToInt64 ( bsonReader . ReadDecimal128 ( ) ) , DateTimeKind . Utc ) ) ;
120- break ;
154+ return VerifyAndMakeDateOnly ( new DateTime ( _converter . ToInt64 ( bsonReader . ReadDecimal128 ( ) ) , DateTimeKind . Utc ) ) ;
121155
122156 case BsonType . Double :
123- value = VerifyAndMakeDateOnly ( new DateTime ( _converter . ToInt64 ( bsonReader . ReadDouble ( ) ) , DateTimeKind . Utc ) ) ;
124- break ;
157+ return VerifyAndMakeDateOnly ( new DateTime ( _converter . ToInt64 ( bsonReader . ReadDouble ( ) ) , DateTimeKind . Utc ) ) ;
125158
126159 case BsonType . Int32 :
127- value = VerifyAndMakeDateOnly ( new DateTime ( bsonReader . ReadInt32 ( ) , DateTimeKind . Utc ) ) ;
128- break ;
160+ return VerifyAndMakeDateOnly ( new DateTime ( bsonReader . ReadInt32 ( ) , DateTimeKind . Utc ) ) ;
129161
130162 case BsonType . Int64 :
131- value = VerifyAndMakeDateOnly ( new DateTime ( bsonReader . ReadInt64 ( ) , DateTimeKind . Utc ) ) ;
132- break ;
163+ return VerifyAndMakeDateOnly ( new DateTime ( bsonReader . ReadInt64 ( ) , DateTimeKind . Utc ) ) ;
133164
134165 case BsonType . String :
135- value = DateOnly . ParseExact ( bsonReader . ReadString ( ) , "yyyy-MM-dd" ) ;
136- break ;
166+ return DateOnly . ParseExact ( bsonReader . ReadString ( ) , "yyyy-MM-dd" ) ;
137167
138168 default :
139169 throw CreateCannotDeserializeFromBsonTypeException ( bsonType ) ;
140170 }
141171
142- return value ;
143172
144173 DateOnly VerifyAndMakeDateOnly ( DateTime dt )
145174 {
@@ -160,7 +189,8 @@ public override bool Equals(object obj)
160189 return
161190 base . Equals ( obj ) &&
162191 obj is DateOnlySerializer other &&
163- _representation . Equals ( other . _representation ) ;
192+ _representation . Equals ( other . _representation ) &&
193+ _documentFormat . Equals ( other . _documentFormat ) ;
164194 }
165195
166196 /// <inheritdoc/>
@@ -182,8 +212,17 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati
182212
183213 case BsonType . Document :
184214 bsonWriter . WriteStartDocument ( ) ;
185- bsonWriter . WriteDateTime ( "DateTime" , millisecondsSinceEpoch ) ;
186- bsonWriter . WriteInt64 ( "Ticks" , utcDateTime . Ticks ) ;
215+ if ( _documentFormat is DateOnlyDocumentFormat . DateTimeTicks )
216+ {
217+ bsonWriter . WriteDateTime ( "DateTime" , millisecondsSinceEpoch ) ;
218+ bsonWriter . WriteInt64 ( "Ticks" , utcDateTime . Ticks ) ;
219+ }
220+ else
221+ {
222+ bsonWriter . WriteInt32 ( "Year" , value . Year ) ;
223+ bsonWriter . WriteInt32 ( "Month" , value . Month ) ;
224+ bsonWriter . WriteInt32 ( "Day" , value . Day ) ;
225+ }
187226 bsonWriter . WriteEndDocument ( ) ;
188227 break ;
189228
@@ -200,10 +239,28 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati
200239 }
201240 }
202241
242+ /// <summary>
243+ /// Returns a serializer that has been reconfigured with the specified representation and document format.
244+ /// </summary>
245+ /// <param name="representation">The representation.</param>
246+ /// <param name="documentFormat">The document format to use with BsonType.Document representation.</param>
247+ /// <returns>
248+ /// The reconfigured serializer.
249+ /// </returns>
250+ public DateOnlySerializer WithRepresentation ( BsonType representation , DateOnlyDocumentFormat documentFormat )
251+ {
252+ if ( representation == _representation && documentFormat == _documentFormat )
253+ {
254+ return this ;
255+ }
256+
257+ return new DateOnlySerializer ( representation , documentFormat ) ;
258+ }
259+
203260 /// <inheritdoc />
204261 public DateOnlySerializer WithRepresentation ( BsonType representation )
205262 {
206- return representation == _representation ? this : new DateOnlySerializer ( representation ) ;
263+ return representation == _representation ? this : new DateOnlySerializer ( representation , _documentFormat ) ;
207264 }
208265
209266 // explicit interface implementations
0 commit comments