mssql_value_serializer/literals/
time.rs1use std::fmt::{self, Formatter, Write};
2
3use time::{Date, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset};
4
5use super::{SqlLiteralError, SqlServerLiteral};
6use crate::impl_dyn_wrapper;
7
8#[inline]
11fn push_naive_date(naive_date: &Date, out: &mut impl Write) -> fmt::Result {
12 write!(
13 out,
14 "{year:04}-{month:02}-{day:02}",
15 year = naive_date.year(),
16 month = naive_date.month() as u8,
17 day = naive_date.day()
18 )
19}
20
21fn push_naive_time(naive_time: &Time, out: &mut impl Write) -> fmt::Result {
22 write!(
23 out,
24 "{hour:02}:{minute:02}:{second:02}",
25 hour = naive_time.hour(),
26 minute = naive_time.minute(),
27 second = naive_time.second(),
28 )?;
29
30 let mut nnnnnnn = (naive_time.nanosecond() / 100) * 100;
31
32 if nnnnnnn > 0 {
33 out.write_char('.')?;
34
35 let digits = nnnnnnn.ilog10() + 1;
36
37 for _ in digits..9 {
38 out.write_char('0')?;
39 }
40
41 while nnnnnnn % 10 == 0 {
43 nnnnnnn /= 10;
44 }
45
46 write!(out, "{nnnnnnn}")?;
47 }
48
49 Ok(())
50}
51
52#[inline]
53fn push_naive_date_time(naive_date_time: &PrimitiveDateTime, out: &mut impl Write) -> fmt::Result {
54 let date = naive_date_time.date();
55 let time = naive_date_time.time();
56
57 push_naive_date(&date, out)?;
58 out.write_char(' ')?;
59 push_naive_time(&time, out)
60}
61
62fn push_time_zone(fixed_offset: &UtcOffset, out: &mut impl Write) -> fmt::Result {
63 let mut hours = fixed_offset.whole_hours();
64 let mut minutes = fixed_offset.minutes_past_hour();
65
66 let sign = if hours >= 0 {
67 '+'
68 } else {
69 hours = -hours;
70 minutes = -minutes;
71
72 '-'
73 };
74
75 debug_assert!(
77 fixed_offset.seconds_past_minute() == 0,
78 "the seconds part of {fixed_offset:?} should be zero for SQL Server"
79 );
80
81 write!(out, "{sign}{hours:02}:{minutes:02}")
82}
83
84#[inline]
85fn push_date_time_utc(naive_date_time: &UtcDateTime, out: &mut impl Write) -> fmt::Result {
86 let date = naive_date_time.date();
87 let time = naive_date_time.time();
88
89 push_naive_date(&date, out)?;
90 out.write_char(' ')?;
91 push_naive_time(&time, out)?;
92
93 out.write_str(" +00:00")
94}
95
96#[inline]
97fn push_date_time_fixed_offset(date_time: &OffsetDateTime, out: &mut impl Write) -> fmt::Result {
98 let date = date_time.date();
99 let time = date_time.time();
100 let time_zone = date_time.offset();
101
102 push_naive_date(&date, out)?;
103 out.write_char(' ')?;
104 push_naive_time(&time, out)?;
105
106 out.write_char(' ')?;
107 push_time_zone(&time_zone, out)
108}
109
110macro_rules! impl_date_time_as_string {
111 ($ty:ty, $f:ident) => {
112 impl SqlServerLiteral for $ty {
113 #[inline]
114 fn append_sql_literal(&self, out: &mut String) -> Result<(), SqlLiteralError> {
115 out.push('\'');
116 $f(self, out).unwrap();
117 out.push('\'');
118
119 Ok(())
120 }
121
122 #[inline]
123 fn append_sql_literal_fmt(
124 &self,
125 out: &mut Formatter<'_>,
126 ) -> Result<(), SqlLiteralError> {
127 out.write_char('\'').unwrap();
128 $f(self, out).unwrap();
129 out.write_char('\'').unwrap();
130
131 Ok(())
132 }
133 }
134
135 impl_dyn_wrapper!($ty);
136 };
137}
138impl_date_time_as_string!(Date, push_naive_date);
139impl_date_time_as_string!(Time, push_naive_time);
140impl_date_time_as_string!(PrimitiveDateTime, push_naive_date_time);
141impl_date_time_as_string!(OffsetDateTime, push_date_time_fixed_offset);
142impl_date_time_as_string!(UtcDateTime, push_date_time_utc);