Skip to content

Commit 1751a27

Browse files
authored
Merge pull request #249 from SeaQL/date-time-local
Add `Value::DateTimeLocal`
2 parents 6c11e64 + 2607239 commit 1751a27

File tree

7 files changed

+86
-2
lines changed

7 files changed

+86
-2
lines changed

src/backend/query_builder.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,8 @@ pub trait QueryBuilder: QuotedBuilder {
939939
#[cfg(feature = "with-chrono")]
940940
Value::DateTimeUtc(None) => write!(s, "NULL").unwrap(),
941941
#[cfg(feature = "with-chrono")]
942+
Value::DateTimeLocal(None) => write!(s, "NULL").unwrap(),
943+
#[cfg(feature = "with-chrono")]
942944
Value::DateTimeWithTimeZone(None) => write!(s, "NULL").unwrap(),
943945
#[cfg(feature = "with-rust_decimal")]
944946
Value::Decimal(None) => write!(s, "NULL").unwrap(),
@@ -981,6 +983,10 @@ pub trait QueryBuilder: QuotedBuilder {
981983
write!(s, "\'{}\'", v.format("%Y-%m-%d %H:%M:%S %:z").to_string()).unwrap()
982984
}
983985
#[cfg(feature = "with-chrono")]
986+
Value::DateTimeLocal(Some(v)) => {
987+
write!(s, "\'{}\'", v.format("%Y-%m-%d %H:%M:%S %:z").to_string()).unwrap()
988+
}
989+
#[cfg(feature = "with-chrono")]
984990
Value::DateTimeWithTimeZone(Some(v)) => {
985991
write!(s, "\'{}\'", v.format("%Y-%m-%d %H:%M:%S %:z").to_string()).unwrap()
986992
}

src/driver/postgres.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ impl ToSql for Value {
5454
#[cfg(feature = "postgres-chrono")]
5555
Value::DateTimeUtc(v) => box_to_sql!(v, chrono::DateTime<chrono::Utc>),
5656
#[cfg(feature = "postgres-chrono")]
57+
Value::DateTimeLocal(v) => box_to_sql!(v, chrono::DateTime<chrono::Local>),
58+
#[cfg(feature = "postgres-chrono")]
5759
Value::DateTimeWithTimeZone(v) => box_to_sql!(v, chrono::DateTime<chrono::FixedOffset>),
5860
#[cfg(feature = "postgres-rust_decimal")]
5961
Value::Decimal(v) => box_to_sql!(v, rust_decimal::Decimal),

src/driver/rusqlite.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ macro_rules! sea_query_driver_rusqlite {
7676
ty_to_sql!(self.0.as_ref_time())
7777
} else if self.0.is_date_time() {
7878
ty_to_sql!(self.0.as_ref_date_time())
79+
} else if self.0.is_date_time_utc() {
80+
ty_to_sql!(self.0.as_ref_date_time_utc())
81+
} else if self.0.is_date_time_local() {
82+
ty_to_sql!(self.0.as_ref_date_time_local())
7983
} else if self.0.is_date_time_with_time_zone() {
8084
ty_to_sql!(self.0.as_ref_date_time_with_time_zone())
8185
} else if self.0.is_uuid() {

src/driver/sqlx_mysql.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ macro_rules! bind_params_sqlx_mysql {
4444
query.bind(value.as_ref_date_time())
4545
} else if value.is_date_time_utc() {
4646
query.bind(value.as_ref_date_time_utc())
47+
} else if value.is_date_time_local() {
48+
query.bind(value.as_ref_date_time_local())
4749
} else if value.is_date_time_with_time_zone() {
4850
query.bind(value.as_naive_utc_in_string())
4951
} else if value.is_decimal() {

src/driver/sqlx_postgres.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ macro_rules! bind_params_sqlx_postgres {
4444
query.bind(value.as_ref_date_time())
4545
} else if value.is_date_time_utc() {
4646
query.bind(value.as_ref_date_time_utc())
47+
} else if value.is_date_time_local() {
48+
query.bind(value.as_ref_date_time_local())
4749
} else if value.is_date_time_with_time_zone() {
4850
query.bind(value.as_ref_date_time_with_time_zone())
4951
} else if value.is_decimal() {

src/driver/sqlx_sqlite.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ macro_rules! bind_params_sqlx_sqlite {
4444
query.bind(value.as_ref_date_time())
4545
} else if value.is_date_time_utc() {
4646
query.bind(value.as_naive_utc_in_string())
47+
} else if value.is_date_time_local() {
48+
query.bind(value.as_naive_utc_in_string())
4749
} else if value.is_date_time_with_time_zone() {
4850
query.bind(value.as_naive_utc_in_string())
4951
} else if value.is_decimal() {

src/value.rs

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use serde_json::Value as Json;
77
use std::str::from_utf8;
88

99
#[cfg(feature = "with-chrono")]
10-
use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Utc};
10+
use chrono::{DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, Utc};
1111

1212
#[cfg(feature = "with-rust_decimal")]
1313
use rust_decimal::Decimal;
@@ -61,6 +61,10 @@ pub enum Value {
6161
#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
6262
DateTimeUtc(Option<Box<DateTime<Utc>>>),
6363

64+
#[cfg(feature = "with-chrono")]
65+
#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
66+
DateTimeLocal(Option<Box<DateTime<Local>>>),
67+
6468
#[cfg(feature = "with-chrono")]
6569
#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
6670
DateTimeWithTimeZone(Option<Box<DateTime<FixedOffset>>>),
@@ -290,7 +294,7 @@ mod with_json {
290294
#[cfg_attr(docsrs, doc(cfg(feature = "with-chrono")))]
291295
mod with_chrono {
292296
use super::*;
293-
use chrono::{Offset, Utc};
297+
use chrono::{Local, Offset, Utc};
294298

295299
type_to_box_value!(NaiveDate, Date, Date);
296300
type_to_box_value!(NaiveTime, Time, Time(None));
@@ -302,6 +306,12 @@ mod with_chrono {
302306
}
303307
}
304308

309+
impl From<DateTime<Local>> for Value {
310+
fn from(v: DateTime<Local>) -> Value {
311+
Value::DateTimeLocal(Some(Box::new(v)))
312+
}
313+
}
314+
305315
impl From<DateTime<FixedOffset>> for Value {
306316
fn from(x: DateTime<FixedOffset>) -> Value {
307317
let v = DateTime::<FixedOffset>::from_utc(x.naive_utc(), x.offset().fix());
@@ -332,6 +342,29 @@ mod with_chrono {
332342
}
333343
}
334344

345+
impl Nullable for DateTime<Local> {
346+
fn null() -> Value {
347+
Value::DateTimeLocal(None)
348+
}
349+
}
350+
351+
impl ValueType for DateTime<Local> {
352+
fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
353+
match v {
354+
Value::DateTimeLocal(Some(x)) => Ok(*x),
355+
_ => Err(ValueTypeErr),
356+
}
357+
}
358+
359+
fn type_name() -> String {
360+
stringify!(DateTime<Local>).to_owned()
361+
}
362+
363+
fn column_type() -> ColumnType {
364+
ColumnType::TimestampWithTimeZone(None)
365+
}
366+
}
367+
335368
impl Nullable for DateTime<FixedOffset> {
336369
fn null() -> Value {
337370
Value::DateTimeWithTimeZone(None)
@@ -563,6 +596,13 @@ impl Value {
563596
#[cfg(not(feature = "with-chrono"))]
564597
return false;
565598
}
599+
600+
pub fn is_date_time_local(&self) -> bool {
601+
#[cfg(feature = "with-chrono")]
602+
return matches!(self, Self::DateTimeLocal(_));
603+
#[cfg(not(feature = "with-chrono"))]
604+
return false;
605+
}
566606
pub fn is_date_time_with_time_zone(&self) -> bool {
567607
#[cfg(feature = "with-chrono")]
568608
return matches!(self, Self::DateTimeWithTimeZone(_));
@@ -582,6 +622,18 @@ impl Value {
582622
panic!("not Value::DateTimeUtc")
583623
}
584624

625+
#[cfg(feature = "with-chrono")]
626+
pub fn as_ref_date_time_local(&self) -> Option<&DateTime<Local>> {
627+
match self {
628+
Self::DateTimeLocal(v) => box_to_opt_ref!(v),
629+
_ => panic!("not Value::DateTimeLocal"),
630+
}
631+
}
632+
#[cfg(not(feature = "with-chrono"))]
633+
pub fn as_ref_date_time_local(&self) -> Option<&bool> {
634+
panic!("not Value::DateTimeLocal")
635+
}
636+
585637
#[cfg(feature = "with-chrono")]
586638
pub fn as_ref_date_time_with_time_zone(&self) -> Option<&DateTime<FixedOffset>> {
587639
match self {
@@ -599,6 +651,7 @@ impl Value {
599651
match self {
600652
Self::DateTime(v) => v.as_ref().map(|v| v.to_string()),
601653
Self::DateTimeUtc(v) => v.as_ref().map(|v| v.naive_utc().to_string()),
654+
Self::DateTimeLocal(v) => v.as_ref().map(|v| v.naive_utc().to_string()),
602655
Self::DateTimeWithTimeZone(v) => v.as_ref().map(|v| v.naive_utc().to_string()),
603656
_ => panic!("not Value::DateTime"),
604657
}
@@ -1024,6 +1077,8 @@ pub fn sea_value_to_json_value(value: &Value) -> Json {
10241077
Value::DateTimeWithTimeZone(_) => CommonSqlQueryBuilder.value_to_string(value).into(),
10251078
#[cfg(feature = "with-chrono")]
10261079
Value::DateTimeUtc(_) => CommonSqlQueryBuilder.value_to_string(value).into(),
1080+
#[cfg(feature = "with-chrono")]
1081+
Value::DateTimeLocal(_) => CommonSqlQueryBuilder.value_to_string(value).into(),
10271082
#[cfg(feature = "with-rust_decimal")]
10281083
Value::Decimal(Some(v)) => {
10291084
use rust_decimal::prelude::ToPrimitive;
@@ -1330,6 +1385,17 @@ mod tests {
13301385
assert_eq!(out, timestamp);
13311386
}
13321387

1388+
#[test]
1389+
#[cfg(feature = "with-chrono")]
1390+
fn test_chrono_local_value() {
1391+
let timestamp_utc =
1392+
DateTime::<Utc>::from_utc(NaiveDate::from_ymd(2022, 1, 2).and_hms(3, 4, 5), Utc);
1393+
let timestamp_local: DateTime<Local> = timestamp_utc.into();
1394+
let value: Value = timestamp_local.into();
1395+
let out: DateTime<Local> = value.unwrap();
1396+
assert_eq!(out, timestamp_local);
1397+
}
1398+
13331399
#[test]
13341400
#[cfg(feature = "with-chrono")]
13351401
fn test_chrono_timezone_value() {

0 commit comments

Comments
 (0)