tiberius_rustls/tds/time/
time.rs1use std::time::Duration;
8pub use time::{Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset};
9
10use crate::tds::codec::ColumnData;
11
12#[inline]
13fn from_days(days: u64, start_year: i32) -> Date {
14 Date::from_calendar_date(start_year, Month::January, 1).unwrap()
15 + Duration::from_secs(60 * 60 * 24 * days)
16}
17
18#[inline]
19#[cfg(feature = "tds73")]
20fn from_secs(secs: u64) -> Time {
21 Time::from_hms(0, 0, 0).unwrap() + Duration::from_secs(secs)
22}
23
24#[inline]
25fn from_sec_fragments(sec_fragments: u64) -> Time {
26 Time::from_hms(0, 0, 0).unwrap() + Duration::from_nanos(sec_fragments * (1e9 as u64) / 300)
27}
28
29#[inline]
30fn to_days(date: Date, start_year: i32) -> i64 {
31 (date - Date::from_calendar_date(start_year, Month::January, 1).unwrap()).whole_days()
32}
33
34#[inline]
35#[cfg(not(feature = "tds73"))]
36fn to_sec_fragments(from: Time) -> i64 {
37 let nanos: i64 = (from - Time::from_hms(0, 0, 0).unwrap())
38 .whole_nanoseconds()
39 .try_into()
40 .unwrap();
41
42 nanos * 300 / (1e9 as i64)
43}
44
45#[cfg(feature = "tds73")]
46from_sql!(
47 PrimitiveDateTime:
48 ColumnData::SmallDateTime(ref dt) => dt.map(|dt| PrimitiveDateTime::new(
49 from_days(dt.days as u64, 1900),
50 from_secs(dt.seconds_fragments as u64 * 60),
51 )),
52 ColumnData::DateTime2(ref dt) => dt.map(|dt| PrimitiveDateTime::new(
53 from_days(dt.date.days() as u64, 1),
54 Time::from_hms(0,0,0).unwrap() + Duration::from_nanos(dt.time.increments * 10u64.pow(9 - dt.time.scale as u32))
55 )),
56 ColumnData::DateTime(ref dt) => dt.map(|dt| PrimitiveDateTime::new(
57 from_days(dt.days as u64, 1900),
58 from_sec_fragments(dt.seconds_fragments as u64)
59 ));
60 Time:
61 ColumnData::Time(ref time) => time.map(|time| {
62 let ns = time.increments * 10u64.pow(9 - time.scale as u32);
63 Time::from_hms(0,0,0).unwrap() + Duration::from_nanos(ns)
64 });
65 Date:
66 ColumnData::Date(ref date) => date.map(|date| from_days(date.days() as u64, 1));
67 OffsetDateTime:
68 ColumnData::DateTimeOffset(ref dto) => dto.map(|dto| {
69 let date = from_days(dto.datetime2.date.days() as u64, 1);
70 let dt = dto.datetime2;
71
72 let time = Time::from_hms(0,0,0).unwrap()
73 + Duration::from_nanos(dt.time.increments * 10u64.pow(9 - dt.time.scale as u32));
74
75 let offset = UtcOffset::from_whole_seconds(dto.offset as i32 * 60).unwrap();
76
77 date.with_time(time).assume_utc().to_offset(offset)
78 })
79);
80
81#[cfg(feature = "tds73")]
82to_sql!(self_,
83 Date: (ColumnData::Date, super::Date::new(to_days(*self_, 1) as u32));
84 Time: (ColumnData::Time, {
85 let nanos: u64 = (*self_ - Time::from_hms(0, 0, 0).unwrap()).whole_nanoseconds().try_into().unwrap();
86 let increments = nanos / 100;
87
88 super::Time {increments, scale: 7}
89 });
90 PrimitiveDateTime: (ColumnData::DateTime2, {
91 let time = self_.time();
92 let nanos: u64 = (time - Time::from_hms(0, 0, 0).unwrap()).whole_nanoseconds().try_into().unwrap();
93 let increments = nanos / 100;
94
95 let date = super::Date::new(to_days(self_.date(), 1) as u32);
96 let time = super::Time {increments, scale: 7};
97
98 super::DateTime2::new(date, time)
99 });
100 OffsetDateTime: (ColumnData::DateTimeOffset, {
101 let tz = self_.offset();
102 let offset = (tz.whole_seconds() / 60) as i16;
103
104 let utc_date = self_.to_offset(UtcOffset::UTC);
105
106 let nanos: u64 = (utc_date.time() - Time::from_hms(0, 0, 0).unwrap()).whole_nanoseconds().try_into().unwrap();
107
108 let date = super::Date::new(to_days(utc_date.date(), 1) as u32);
109 let time = super::Time { increments: nanos / 100, scale: 7 };
110
111 super::DateTimeOffset::new(super::DateTime2::new(date, time), offset)
112 });
113);
114
115#[cfg(not(feature = "tds73"))]
116to_sql!(self_,
117 PrimitiveDateTime: (ColumnData::DateTime, {
118 let date = self_.date();
119 let time = self_.time();
120
121 let days = to_days(date, 1900) as i32;
122 let seconds_fragments = to_sec_fragments(time);
123
124 super::DateTime::new(days, seconds_fragments as u32)
125 });
126);
127
128#[cfg(not(feature = "tds73"))]
129from_sql!(
130 PrimitiveDateTime:
131 ColumnData::DateTime(ref dt) => dt.map(|dt| {
132 from_days(dt.days as u64, 1900).with_time(from_sec_fragments(dt.seconds_fragments as u64))
133 })
134);