1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
use crate::types::*; use chrono::{FixedOffset, NaiveTime, Offset, Timelike}; use neo4rs_macros::BoltStruct; #[derive(Debug, PartialEq, Clone, Hash, BoltStruct)] #[signature(0xB2, 0x54)] pub struct BoltTime { nanoseconds: BoltInteger, tz_offset_seconds: BoltInteger, } #[derive(Debug, PartialEq, Clone, Hash, BoltStruct)] #[signature(0xB1, 0x74)] pub struct BoltLocalTime { nanoseconds: BoltInteger, } impl Into<BoltTime> for (NaiveTime, FixedOffset) { fn into(self) -> BoltTime { let seconds_from_midnight = self.0.num_seconds_from_midnight() as i64; let nanoseconds = seconds_from_midnight * 1_000_000_000 + self.0.nanosecond() as i64; BoltTime { nanoseconds: nanoseconds.into(), tz_offset_seconds: self.1.fix().local_minus_utc().into(), } } } impl Into<(NaiveTime, FixedOffset)> for BoltTime { fn into(self) -> (NaiveTime, FixedOffset) { let nanos = self.nanoseconds.value; let seconds = (nanos / 1_000_000_000) as u32; let nanoseconds = (nanos % 1_000_000_000) as u32; ( NaiveTime::from_num_seconds_from_midnight(seconds, nanoseconds), FixedOffset::east(self.tz_offset_seconds.value as i32), ) } } impl Into<BoltLocalTime> for NaiveTime { fn into(self) -> BoltLocalTime { let seconds_from_midnight = self.num_seconds_from_midnight() as i64; let nanoseconds = seconds_from_midnight * 1_000_000_000 + self.nanosecond() as i64; BoltLocalTime { nanoseconds: nanoseconds.into(), } } } impl Into<NaiveTime> for BoltLocalTime { fn into(self) -> NaiveTime { let nanos = self.nanoseconds.value; let seconds = (nanos / 1_000_000_000) as u32; let nanoseconds = (nanos % 1_000_000_000) as u32; NaiveTime::from_num_seconds_from_midnight(seconds, nanoseconds) } } #[cfg(test)] mod tests { use super::*; use crate::version::Version; use bytes::*; use std::cell::RefCell; use std::rc::Rc; #[test] fn should_serialize_time() { let time = NaiveTime::from_hms_nano_opt(7, 8, 9, 100).unwrap(); let offset = FixedOffset::east(2 * 3600); let time: BoltTime = (time, offset).into(); assert_eq!( time.to_bytes(Version::V4_1).unwrap(), Bytes::from_static(&[ 0xB2, 0x54, 0xCB, 0x00, 0x00, 0x17, 0x5D, 0x2F, 0xB8, 0x3A, 0x64, 0xC9, 0x1C, 0x20, ]) ); } #[test] fn should_deserialize_time() { let bytes = Rc::new(RefCell::new(Bytes::from_static(&[ 0xB2, 0x54, 0xCB, 0x00, 0x00, 0x17, 0x5D, 0x2F, 0xB8, 0x3A, 0x64, 0xC9, 0x1C, 0x20, ]))); let (time, offset) = BoltTime::parse(Version::V4_1, bytes) .unwrap() .try_into() .unwrap(); assert_eq!(time.to_string(), "07:08:09.000000100"); assert_eq!(offset, FixedOffset::east(2 * 3600)); } #[test] fn should_serialize_local_time() { let naive_time = NaiveTime::from_hms_nano_opt(7, 8, 9, 100).unwrap(); let time: BoltLocalTime = naive_time.into(); assert_eq!( time.to_bytes(Version::V4_1).unwrap(), Bytes::from_static(&[ 0xB1, 0x74, 0xCB, 0x00, 0x00, 0x17, 0x5D, 0x2F, 0xB8, 0x3A, 0x64, ]) ); } #[test] fn should_deserialize_local_time() { let bytes = Rc::new(RefCell::new(Bytes::from_static(&[ 0xB1, 0x74, 0xCB, 0x00, 0x00, 0x17, 0x5D, 0x2F, 0xB8, 0x3A, 0x64, ]))); let time: NaiveTime = BoltLocalTime::parse(Version::V4_1, bytes) .unwrap() .try_into() .unwrap(); assert_eq!(time.to_string(), "07:08:09.000000100"); } }