Skip to main content

fory_core/serializer/
datetime.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::context::ReadContext;
19use crate::context::WriteContext;
20use crate::error::Error;
21use crate::resolver::TypeResolver;
22use crate::serializer::util::read_basic_type_info;
23use crate::serializer::ForyDefault;
24use crate::serializer::Serializer;
25use crate::type_id::TypeId;
26use crate::types::{Date, Duration, Timestamp};
27use std::mem;
28
29impl Serializer for Timestamp {
30    #[inline(always)]
31    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
32        context.writer.write_i64(self.seconds());
33        context.writer.write_u32(self.subsec_nanos());
34        Ok(())
35    }
36
37    #[inline(always)]
38    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
39        let seconds = context.reader.read_i64()?;
40        let nanos = context.reader.read_u32()?;
41        Timestamp::new(seconds, nanos)
42    }
43
44    #[inline(always)]
45    fn fory_reserved_space() -> usize {
46        mem::size_of::<i64>() + mem::size_of::<u32>()
47    }
48
49    #[inline(always)]
50    fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
51        Ok(TypeId::TIMESTAMP)
52    }
53
54    #[inline(always)]
55    fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
56        Ok(TypeId::TIMESTAMP)
57    }
58
59    #[inline(always)]
60    fn fory_static_type_id() -> TypeId {
61        TypeId::TIMESTAMP
62    }
63
64    #[inline(always)]
65    fn as_any(&self) -> &dyn std::any::Any {
66        self
67    }
68
69    #[inline(always)]
70    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
71        context.writer.write_u8(TypeId::TIMESTAMP as u8);
72        Ok(())
73    }
74
75    #[inline(always)]
76    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
77        read_basic_type_info::<Self>(context)
78    }
79}
80
81impl ForyDefault for Timestamp {
82    #[inline(always)]
83    fn fory_default() -> Self {
84        Timestamp::default()
85    }
86}
87
88impl Serializer for Date {
89    #[inline(always)]
90    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
91        let days = self.epoch_days();
92        if context.is_xlang() {
93            context.writer.write_var_i64(days);
94        } else {
95            let native_days = i32::try_from(days).map_err(|_| {
96                Error::invalid_data(format!("date day count {} exceeds native i32 range", days))
97            })?;
98            context.writer.write_i32(native_days);
99        }
100        Ok(())
101    }
102
103    #[inline(always)]
104    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
105        let days = if context.is_xlang() {
106            context.reader.read_var_i64()?
107        } else {
108            i64::from(context.reader.read_i32()?)
109        };
110        Ok(Date::from_epoch_days(days))
111    }
112
113    #[inline(always)]
114    fn fory_reserved_space() -> usize {
115        9
116    }
117
118    #[inline(always)]
119    fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
120        Ok(TypeId::DATE)
121    }
122
123    #[inline(always)]
124    fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
125        Ok(TypeId::DATE)
126    }
127
128    #[inline(always)]
129    fn fory_static_type_id() -> TypeId {
130        TypeId::DATE
131    }
132
133    #[inline(always)]
134    fn as_any(&self) -> &dyn std::any::Any {
135        self
136    }
137
138    #[inline(always)]
139    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
140        context.writer.write_u8(TypeId::DATE as u8);
141        Ok(())
142    }
143
144    #[inline(always)]
145    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
146        read_basic_type_info::<Self>(context)
147    }
148}
149
150impl ForyDefault for Date {
151    #[inline(always)]
152    fn fory_default() -> Self {
153        Date::default()
154    }
155}
156
157impl Serializer for Duration {
158    #[inline(always)]
159    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
160        context.writer.write_var_i64(self.seconds());
161        context.writer.write_i32(self.subsec_nanos() as i32);
162        Ok(())
163    }
164
165    #[inline(always)]
166    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
167        let seconds = context.reader.read_var_i64()?;
168        let nanos = context.reader.read_i32()?;
169        Duration::new(seconds, nanos)
170    }
171
172    #[inline(always)]
173    fn fory_reserved_space() -> usize {
174        9 + mem::size_of::<i32>()
175    }
176
177    #[inline(always)]
178    fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
179        Ok(TypeId::DURATION)
180    }
181
182    #[inline(always)]
183    fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
184        Ok(TypeId::DURATION)
185    }
186
187    #[inline(always)]
188    fn fory_static_type_id() -> TypeId {
189        TypeId::DURATION
190    }
191
192    #[inline(always)]
193    fn as_any(&self) -> &dyn std::any::Any {
194        self
195    }
196
197    #[inline(always)]
198    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
199        context.writer.write_u8(TypeId::DURATION as u8);
200        Ok(())
201    }
202
203    #[inline(always)]
204    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
205        read_basic_type_info::<Self>(context)
206    }
207}
208
209impl ForyDefault for Duration {
210    #[inline(always)]
211    fn fory_default() -> Self {
212        Duration::default()
213    }
214}
215
216#[cfg(feature = "chrono")]
217mod chrono_support {
218    use super::*;
219    use chrono::{Duration as ChronoDuration, NaiveDate, NaiveDateTime};
220
221    impl Serializer for NaiveDateTime {
222        #[inline(always)]
223        fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
224            Timestamp::from(*self).fory_write_data(context)
225        }
226
227        #[inline(always)]
228        fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
229            Timestamp::fory_read_data(context)?.try_into()
230        }
231
232        #[inline(always)]
233        fn fory_reserved_space() -> usize {
234            Timestamp::fory_reserved_space()
235        }
236
237        #[inline(always)]
238        fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
239            Ok(TypeId::TIMESTAMP)
240        }
241
242        #[inline(always)]
243        fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
244            Ok(TypeId::TIMESTAMP)
245        }
246
247        #[inline(always)]
248        fn fory_static_type_id() -> TypeId {
249            TypeId::TIMESTAMP
250        }
251
252        #[inline(always)]
253        fn as_any(&self) -> &dyn std::any::Any {
254            self
255        }
256
257        #[inline(always)]
258        fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
259            Timestamp::fory_write_type_info(context)
260        }
261
262        #[inline(always)]
263        fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
264            read_basic_type_info::<Self>(context)
265        }
266    }
267
268    impl ForyDefault for NaiveDateTime {
269        #[inline(always)]
270        fn fory_default() -> Self {
271            NaiveDateTime::default()
272        }
273    }
274
275    impl Serializer for NaiveDate {
276        #[inline(always)]
277        fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
278            Date::from(*self).fory_write_data(context)
279        }
280
281        #[inline(always)]
282        fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
283            Date::fory_read_data(context)?.try_into()
284        }
285
286        #[inline(always)]
287        fn fory_reserved_space() -> usize {
288            Date::fory_reserved_space()
289        }
290
291        #[inline(always)]
292        fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
293            Ok(TypeId::DATE)
294        }
295
296        #[inline(always)]
297        fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
298            Ok(TypeId::DATE)
299        }
300
301        #[inline(always)]
302        fn fory_static_type_id() -> TypeId {
303            TypeId::DATE
304        }
305
306        #[inline(always)]
307        fn as_any(&self) -> &dyn std::any::Any {
308            self
309        }
310
311        #[inline(always)]
312        fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
313            Date::fory_write_type_info(context)
314        }
315
316        #[inline(always)]
317        fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
318            read_basic_type_info::<Self>(context)
319        }
320    }
321
322    impl ForyDefault for NaiveDate {
323        #[inline(always)]
324        fn fory_default() -> Self {
325            NaiveDate::default()
326        }
327    }
328
329    impl Serializer for ChronoDuration {
330        #[inline(always)]
331        fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
332            Duration::try_from(*self)?.fory_write_data(context)
333        }
334
335        #[inline(always)]
336        fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
337            Duration::fory_read_data(context)?.try_into()
338        }
339
340        #[inline(always)]
341        fn fory_reserved_space() -> usize {
342            Duration::fory_reserved_space()
343        }
344
345        #[inline(always)]
346        fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
347            Ok(TypeId::DURATION)
348        }
349
350        #[inline(always)]
351        fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
352            Ok(TypeId::DURATION)
353        }
354
355        #[inline(always)]
356        fn fory_static_type_id() -> TypeId {
357            TypeId::DURATION
358        }
359
360        #[inline(always)]
361        fn as_any(&self) -> &dyn std::any::Any {
362            self
363        }
364
365        #[inline(always)]
366        fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
367            Duration::fory_write_type_info(context)
368        }
369
370        #[inline(always)]
371        fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
372            read_basic_type_info::<Self>(context)
373        }
374    }
375
376    impl ForyDefault for ChronoDuration {
377        #[inline(always)]
378        fn fory_default() -> Self {
379            ChronoDuration::zero()
380        }
381    }
382}
383
384#[cfg(test)]
385mod tests {
386    use super::*;
387    use crate::fory::Fory;
388
389    #[test]
390    fn test_temporal_carrier_serialization() {
391        let fory = Fory::builder().xlang(false).build();
392
393        let timestamps = [
394            Timestamp::UNIX_EPOCH,
395            Timestamp::new(1, 0).unwrap(),
396            Timestamp::new(-1, 999_999_999).unwrap(),
397        ];
398        for timestamp in timestamps {
399            let bytes = fory.serialize(&timestamp).unwrap();
400            let deserialized: Timestamp = fory.deserialize(&bytes).unwrap();
401            assert_eq!(timestamp, deserialized);
402        }
403
404        let dates = [
405            Date::UNIX_EPOCH,
406            Date::from_epoch_days(-1),
407            Date::from_epoch_days(18_628),
408        ];
409        for date in dates {
410            let bytes = fory.serialize(&date).unwrap();
411            let deserialized: Date = fory.deserialize(&bytes).unwrap();
412            assert_eq!(date, deserialized);
413        }
414
415        let durations = [
416            Duration::ZERO,
417            Duration::new(1, 0).unwrap(),
418            Duration::new(0, -1).unwrap(),
419            Duration::new(-123, 456_789).unwrap(),
420        ];
421        for duration in durations {
422            let bytes = fory.serialize(&duration).unwrap();
423            let deserialized: Duration = fory.deserialize(&bytes).unwrap();
424            assert_eq!(duration, deserialized);
425        }
426    }
427
428    #[test]
429    fn test_duration_normalizes_negative_nanoseconds() {
430        assert_eq!(
431            Duration::new(0, -1).unwrap(),
432            Duration::from_normalized(-1, 999_999_999).unwrap()
433        );
434    }
435
436    #[cfg(feature = "chrono")]
437    #[test]
438    fn test_chrono_temporal_feature_serialization() {
439        use chrono::{DateTime, Duration as ChronoDuration, NaiveDate, NaiveDateTime};
440
441        let fory = Fory::builder().xlang(false).build();
442        let date = NaiveDate::from_ymd_opt(2024, 2, 3).unwrap();
443        let timestamp = DateTime::from_timestamp(100, 1).unwrap().naive_utc();
444        let duration = ChronoDuration::nanoseconds(-1);
445
446        let bytes = fory.serialize(&date).unwrap();
447        let deserialized: NaiveDate = fory.deserialize(&bytes).unwrap();
448        assert_eq!(date, deserialized);
449
450        let bytes = fory.serialize(&timestamp).unwrap();
451        let deserialized: NaiveDateTime = fory.deserialize(&bytes).unwrap();
452        assert_eq!(timestamp, deserialized);
453
454        let bytes = fory.serialize(&duration).unwrap();
455        let deserialized: ChronoDuration = fory.deserialize(&bytes).unwrap();
456        assert_eq!(duration, deserialized);
457    }
458}