mssql_value_serializer/literals/
chrono.rs1use std::fmt::{self, Formatter, Write};
2
3use chrono::prelude::*;
4
5use super::{SqlLiteralError, SqlServerLiteral};
6use crate::impl_dyn_wrapper;
7
8#[inline]
11fn push_naive_date(naive_date: &NaiveDate, 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(),
17 day = naive_date.day()
18 )
19}
20
21fn push_naive_time(naive_time: &NaiveTime, 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: &NaiveDateTime, 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: &FixedOffset, out: &mut impl Write) -> fmt::Result {
63 let seconds = fixed_offset.local_minus_utc();
64
65 let (sign, abs_seconds) = if seconds >= 0 { ('+', seconds) } else { ('-', -seconds) };
66
67 let hours = abs_seconds / 3600;
68 let minutes = (abs_seconds % 3600) / 60;
69
70 debug_assert!(
72 abs_seconds % 60 == 0,
73 "the seconds part of {fixed_offset:?} should be zero for SQL Server"
74 );
75
76 write!(out, "{sign}{hours:02}:{minutes:02}")
77}
78
79#[inline]
80fn push_date_time_fixed_offset(
81 date_time: &DateTime<FixedOffset>,
82 out: &mut impl Write,
83) -> fmt::Result {
84 let ndt = date_time.naive_local();
85 let time_zone = date_time.timezone();
86
87 push_naive_date_time(&ndt, out)?;
88 out.write_char(' ')?;
89 push_time_zone(&time_zone, out)
90}
91
92#[inline]
93fn push_date_time_utc(date_time: &DateTime<Utc>, out: &mut impl Write) -> fmt::Result {
94 let ndt = date_time.naive_utc();
95
96 push_naive_date_time(&ndt, out)?;
97 out.write_str(" +00:00")
98}
99
100#[cfg(feature = "stable-local")]
101fn push_date_time_local(date_time: &DateTime<Local>, out: &mut impl Write) -> fmt::Result {
102 use std::sync::Once;
103
104 static INIT: Once = Once::new();
105 static mut TIME_ZONE_STRING: String = String::new();
106
107 INIT.call_once(|| {
108 println!("call once");
109 let fixed_offset = date_time.offset().fix();
110
111 #[allow(static_mut_refs)]
112 unsafe {
113 TIME_ZONE_STRING.reserve(7);
114
115 TIME_ZONE_STRING.push(' ');
116 push_time_zone(&fixed_offset, &mut TIME_ZONE_STRING).unwrap(); }
118 });
119
120 let ndt = date_time.naive_local();
121
122 push_naive_date_time(&ndt, out)?;
123
124 #[allow(static_mut_refs)]
125 out.write_str(unsafe { TIME_ZONE_STRING.as_str() })
126}
127
128#[cfg(not(feature = "stable-local"))]
129#[inline]
130fn push_date_time_local(date_time: &DateTime<Local>, out: &mut impl Write) -> fmt::Result {
131 let date_time = date_time.fixed_offset();
132
133 push_date_time_fixed_offset(&date_time, out)
134}
135
136macro_rules! impl_date_time_as_string {
137 ($ty:ty, $f:ident) => {
138 impl SqlServerLiteral for $ty {
139 #[inline]
140 fn append_sql_literal(&self, out: &mut String) -> Result<(), SqlLiteralError> {
141 out.push('\'');
142 $f(self, out).unwrap();
143 out.push('\'');
144
145 Ok(())
146 }
147
148 #[inline]
149 fn append_sql_literal_fmt(
150 &self,
151 out: &mut Formatter<'_>,
152 ) -> Result<(), SqlLiteralError> {
153 out.write_char('\'').unwrap();
154 $f(self, out).unwrap();
155 out.write_char('\'').unwrap();
156
157 Ok(())
158 }
159 }
160
161 impl_dyn_wrapper!($ty);
162 };
163}
164impl_date_time_as_string!(NaiveDate, push_naive_date);
165impl_date_time_as_string!(NaiveTime, push_naive_time);
166impl_date_time_as_string!(NaiveDateTime, push_naive_date_time);
167impl_date_time_as_string!(DateTime<FixedOffset>, push_date_time_fixed_offset);
168impl_date_time_as_string!(DateTime<Utc>, push_date_time_utc);
169impl_date_time_as_string!(DateTime<Local>, push_date_time_local);