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
+
16
+ using System ;
17
+ using MongoDB . Bson . Serialization . Options ;
18
+
19
+ namespace MongoDB . Bson . Serialization . Serializers
20
+ {
21
+ #if NET6_0_OR_GREATER
22
+ /// <summary>
23
+ /// Represents a serializer for TimeOnlys
24
+ /// </summary>
25
+ public sealed class TimeOnlySerializer : StructSerializerBase < TimeOnly > , IRepresentationConfigurable < TimeOnlySerializer >
26
+ {
27
+ // static
28
+ private static readonly TimeOnlySerializer __instance = new ( ) ;
29
+
30
+ /// <summary>
31
+ /// Gets the default TimeOnlySerializer
32
+ /// </summary>
33
+ public static TimeOnlySerializer Instance => __instance ;
34
+
35
+ // private fields
36
+ private readonly BsonType _representation ;
37
+ private readonly TimeOnlyUnits _units ;
38
+
39
+ // constructors
40
+ /// <summary>
41
+ /// Initializes a new instance of the <see cref="TimeOnlySerializer"/> class.
42
+ /// </summary>
43
+ public TimeOnlySerializer ( )
44
+ : this ( BsonType . Int64 , TimeOnlyUnits . Ticks )
45
+ {
46
+ }
47
+
48
+ /// <summary>
49
+ /// Initializes a new instance of the <see cref="TimeOnlySerializer"/> class.
50
+ /// </summary>
51
+ /// <param name="representation">The representation.</param>
52
+ public TimeOnlySerializer ( BsonType representation )
53
+ : this ( representation , TimeOnlyUnits . Ticks )
54
+ {
55
+ }
56
+
57
+ /// <summary>
58
+ /// Initializes a new instance of the <see cref="TimeOnlySerializer"/> class.
59
+ /// </summary>
60
+ /// <param name="representation">The representation.</param>
61
+ /// <param name="units">The units.</param>
62
+ public TimeOnlySerializer ( BsonType representation , TimeOnlyUnits units )
63
+ {
64
+ switch ( representation )
65
+ {
66
+ case BsonType . Double :
67
+ case BsonType . Int32 :
68
+ case BsonType . Int64 :
69
+ case BsonType . String :
70
+ break ;
71
+
72
+ default :
73
+ throw new ArgumentException ( $ "{ representation } is not a valid representation for a TimeOnlySerializer.") ;
74
+ }
75
+
76
+ _representation = representation ;
77
+ _units = units ;
78
+ }
79
+
80
+ // public properties
81
+ /// <inheritdoc />
82
+ public BsonType Representation => _representation ;
83
+
84
+ /// <summary>
85
+ /// Gets the units.
86
+ /// </summary>
87
+ /// <value>
88
+ /// The units.
89
+ /// </value>
90
+ public TimeOnlyUnits Units => _units ;
91
+
92
+ // public methods
93
+ /// <inheritdoc/>
94
+ public override TimeOnly Deserialize ( BsonDeserializationContext context , BsonDeserializationArgs args )
95
+ {
96
+ var bsonReader = context . Reader ;
97
+ var bsonType = bsonReader . GetCurrentBsonType ( ) ;
98
+
99
+ return bsonType switch
100
+ {
101
+ BsonType . String => TimeOnly . ParseExact ( bsonReader . ReadString ( ) , "o" ) ,
102
+ BsonType . Int64 => FromInt64 ( bsonReader . ReadInt64 ( ) , _units ) ,
103
+ BsonType . Int32 => FromInt32 ( bsonReader . ReadInt32 ( ) , _units ) ,
104
+ BsonType . Double => FromDouble ( bsonReader . ReadDouble ( ) , _units ) ,
105
+ _ => throw CreateCannotDeserializeFromBsonTypeException ( bsonType )
106
+ } ;
107
+ }
108
+
109
+ /// <inheritdoc/>
110
+ public override bool Equals ( object obj )
111
+ {
112
+ if ( object . ReferenceEquals ( obj , null ) ) { return false ; }
113
+ if ( object . ReferenceEquals ( this , obj ) ) { return true ; }
114
+
115
+ return
116
+ base . Equals ( obj ) &&
117
+ obj is TimeOnlySerializer other &&
118
+ _representation . Equals ( other . _representation ) &&
119
+ _units . Equals ( other . _units ) ;
120
+ }
121
+
122
+ /// <inheritdoc/>
123
+ public override int GetHashCode ( ) => 0 ;
124
+
125
+ /// <inheritdoc />
126
+ public override void Serialize ( BsonSerializationContext context , BsonSerializationArgs args , TimeOnly value )
127
+ {
128
+ var bsonWriter = context . Writer ;
129
+
130
+ switch ( _representation )
131
+ {
132
+ case BsonType . Double :
133
+ bsonWriter . WriteDouble ( ToDouble ( value , _units ) ) ;
134
+ break ;
135
+
136
+ case BsonType . Int32 :
137
+ bsonWriter . WriteInt32 ( ToInt32 ( value , _units ) ) ;
138
+ break ;
139
+
140
+ case BsonType . Int64 :
141
+ bsonWriter . WriteInt64 ( ToInt64 ( value , _units ) ) ;
142
+ break ;
143
+
144
+ case BsonType . String :
145
+ bsonWriter . WriteString ( value . ToString ( "o" ) ) ;
146
+ break ;
147
+
148
+ default :
149
+ throw new BsonSerializationException ( $ "'{ _representation } ' is not a valid TimeOnly representation.") ;
150
+ }
151
+ }
152
+
153
+ /// <inheritdoc />
154
+ public TimeOnlySerializer WithRepresentation ( BsonType representation )
155
+ {
156
+ return representation == _representation ? this : new TimeOnlySerializer ( representation ) ;
157
+ }
158
+
159
+ /// <summary>
160
+ /// Returns a serializer that has been reconfigured with the specified representation and units.
161
+ /// </summary>
162
+ /// <param name="representation">The representation.</param>
163
+ /// <param name="units">The units.</param>
164
+ /// <returns>
165
+ /// The reconfigured serializer.
166
+ /// </returns>
167
+ public TimeOnlySerializer WithRepresentation ( BsonType representation , TimeOnlyUnits units )
168
+ {
169
+ if ( representation == _representation && units == _units )
170
+ {
171
+ return this ;
172
+ }
173
+
174
+ return new TimeOnlySerializer ( representation , units ) ;
175
+ }
176
+
177
+ // private methods
178
+ private TimeOnly FromDouble ( double value , TimeOnlyUnits units )
179
+ {
180
+ return units is TimeOnlyUnits . Nanoseconds
181
+ ? new TimeOnly ( ( long ) ( value / 100.0 ) )
182
+ : new TimeOnly ( ( long ) ( value * TicksPerUnit ( units ) ) ) ;
183
+ }
184
+
185
+ private TimeOnly FromInt32 ( int value , TimeOnlyUnits units )
186
+ {
187
+ return units is TimeOnlyUnits . Nanoseconds
188
+ ? new TimeOnly ( value / 100 )
189
+ : new TimeOnly ( value * TicksPerUnit ( units ) ) ;
190
+ }
191
+
192
+ private TimeOnly FromInt64 ( long value , TimeOnlyUnits units )
193
+ {
194
+ return units is TimeOnlyUnits . Nanoseconds
195
+ ? new TimeOnly ( value / 100 )
196
+ : new TimeOnly ( value * TicksPerUnit ( units ) ) ;
197
+ }
198
+
199
+ private long TicksPerUnit ( TimeOnlyUnits units )
200
+ {
201
+ return units switch
202
+ {
203
+ TimeOnlyUnits . Hours => TimeSpan . TicksPerHour ,
204
+ TimeOnlyUnits . Minutes => TimeSpan . TicksPerMinute ,
205
+ TimeOnlyUnits . Seconds => TimeSpan . TicksPerSecond ,
206
+ TimeOnlyUnits . Milliseconds => TimeSpan . TicksPerMillisecond ,
207
+ TimeOnlyUnits . Microseconds => TimeSpan . TicksPerMillisecond / 1000 ,
208
+ TimeOnlyUnits . Ticks => 1 ,
209
+ _ => throw new ArgumentException ( $ "Invalid TimeOnlyUnits value: { units } .")
210
+ } ;
211
+ }
212
+
213
+ private double ToDouble ( TimeOnly timeOnly , TimeOnlyUnits units )
214
+ {
215
+ return units is TimeOnlyUnits . Nanoseconds
216
+ ? timeOnly . Ticks * 100
217
+ : timeOnly . Ticks / ( double ) TicksPerUnit ( units ) ;
218
+ }
219
+
220
+ private int ToInt32 ( TimeOnly timeOnly , TimeOnlyUnits units )
221
+ {
222
+ return units is TimeOnlyUnits . Nanoseconds
223
+ ? ( int ) ( timeOnly . Ticks * 100 )
224
+ : ( int ) ( timeOnly . Ticks / TicksPerUnit ( units ) ) ;
225
+ }
226
+
227
+ private long ToInt64 ( TimeOnly timeOnly , TimeOnlyUnits units )
228
+ {
229
+ return units is TimeOnlyUnits . Nanoseconds
230
+ ? timeOnly . Ticks * 100
231
+ : timeOnly . Ticks / TicksPerUnit ( units ) ;
232
+ }
233
+
234
+ // explicit interface implementations
235
+ IBsonSerializer IRepresentationConfigurable . WithRepresentation ( BsonType representation )
236
+ {
237
+ return WithRepresentation ( representation ) ;
238
+ }
239
+ }
240
+ #endif
241
+ }
0 commit comments