rsfbclient_core/
date_time.rs1use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
2
3use crate::{
4 error::{err_column_null, err_type_conv},
5 ibase, Column, ColumnToVal, FbError, IntoParam, SqlType,
6};
7
8const FRACTION_TO_NANOS: u32 = 1e9 as u32 / ibase::ISC_TIME_SECONDS_PRECISION;
9
10pub fn decode_date(date: ibase::ISC_DATE) -> NaiveDate {
25 let mut nday = date;
26
27 nday += 2400001 - 1721119;
28
29 let century = (4 * nday - 1) / 146097;
30 nday = 4 * nday - 1 - 146097 * century;
31
32 let mut day = nday / 4;
33 nday = (4 * day + 3) / 1461;
34 day = 4 * day + 3 - 1461 * nday;
35 day = (day + 4) / 4;
36
37 let mut month = (5 * day - 3) / 153;
38 day = 5 * day - 3 - 153 * month;
39 day = (day + 5) / 5;
40
41 let mut year = 100 * century + nday;
42
43 if month < 10 {
44 month += 3;
45 } else {
46 month -= 9;
47 year += 1;
48 };
49
50 chrono::NaiveDate::from_ymd(year, month as u32, day as u32)
51}
52
53pub fn encode_date(date: NaiveDate) -> ibase::ISC_DATE {
55 let day = date.day() as i64;
56 let mut month = date.month() as i64;
57 let mut year = date.year() as i64;
58
59 if month > 2 {
60 month -= 3;
61 } else {
62 month += 9;
63 year -= 1;
64 }
65
66 let c = year / 100;
67 let ya = year - 100 * c;
68
69 ((146097 * c) as i64 / 4 + (1461 * ya) / 4 + (153 * month + 2) / 5 + day + 1721119 - 2400001)
70 as ibase::ISC_DATE
71}
72
73pub fn decode_time(time: ibase::ISC_TIME) -> NaiveTime {
75 let mut ntime = time;
76
77 let hours = ntime / (3600 * ibase::ISC_TIME_SECONDS_PRECISION);
78 ntime %= 3600 * ibase::ISC_TIME_SECONDS_PRECISION;
79
80 let minutes = ntime / (60 * ibase::ISC_TIME_SECONDS_PRECISION);
81 ntime %= 60 * ibase::ISC_TIME_SECONDS_PRECISION;
82
83 let seconds = ntime / ibase::ISC_TIME_SECONDS_PRECISION;
84
85 let fraction = ntime % ibase::ISC_TIME_SECONDS_PRECISION;
86
87 chrono::NaiveTime::from_hms_nano(hours, minutes, seconds, fraction * FRACTION_TO_NANOS)
88}
89
90pub fn encode_time(time: chrono::NaiveTime) -> ibase::ISC_TIME {
92 let hours = time.hour();
93 let minutes = time.minute();
94 let seconds = time.second();
95 let fraction = time.nanosecond() / FRACTION_TO_NANOS;
96
97 ((hours * 60 + minutes) * 60 + seconds) * ibase::ISC_TIME_SECONDS_PRECISION + fraction
98}
99
100pub fn decode_timestamp(ts: ibase::ISC_TIMESTAMP) -> NaiveDateTime {
102 decode_date(ts.timestamp_date).and_time(decode_time(ts.timestamp_time))
103}
104
105pub fn encode_timestamp(dt: NaiveDateTime) -> ibase::ISC_TIMESTAMP {
107 ibase::ISC_TIMESTAMP {
108 timestamp_date: encode_date(dt.date()),
109 timestamp_time: encode_time(dt.time()),
110 }
111}
112
113impl IntoParam for NaiveDateTime {
114 fn into_param(self) -> SqlType {
115 SqlType::Timestamp(self)
116 }
117}
118
119impl IntoParam for NaiveDate {
120 fn into_param(self) -> SqlType {
121 self.and_time(NaiveTime::from_hms(0, 0, 0)).into_param()
123 }
124}
125
126impl IntoParam for NaiveTime {
127 fn into_param(self) -> SqlType {
128 chrono::Utc::today().naive_utc().and_time(self).into_param()
130 }
131}
132
133impl ColumnToVal<chrono::NaiveDate> for Column {
134 fn to_val(self) -> Result<chrono::NaiveDate, FbError> {
135 match self.value {
136 SqlType::Timestamp(ts) => Ok(ts.date()),
137
138 SqlType::Null => Err(err_column_null("NaiveDate")),
139
140 col => err_type_conv(col, "NaiveDate"),
141 }
142 }
143}
144
145impl ColumnToVal<chrono::NaiveTime> for Column {
146 fn to_val(self) -> Result<chrono::NaiveTime, FbError> {
147 match self.value {
148 SqlType::Timestamp(ts) => Ok(ts.time()),
149
150 SqlType::Null => Err(err_column_null("NaiveTime")),
151
152 col => err_type_conv(col, "NaiveTime"),
153 }
154 }
155}
156
157impl ColumnToVal<chrono::NaiveDateTime> for Column {
158 fn to_val(self) -> Result<chrono::NaiveDateTime, FbError> {
159 match self.value {
160 SqlType::Timestamp(ts) => Ok(ts),
161
162 SqlType::Null => Err(err_column_null("NaiveDateTime")),
163
164 col => err_type_conv(col, "NaiveDateTime"),
165 }
166 }
167}