DateTime<Utc> 编译但 DateTime<Local> 查询 table 列定义为带时区的时间戳
DateTime<Utc> compiles but not DateTime<Local> querying a table with a column defined as timestamp with time zone
我有一个 postgresql-table,其列定义为 timestamp with time zone
。 table 映射到此结构:
#[derive(Serialize, Queryable)]
pub struct Location {
pub publication_time: DateTime<Utc>,
pub id: i32,
pub name: String,
pub latitude: BigDecimal,
pub longitude: BigDecimal,
}
架构有这样的定义:
table! {
locations {
publication_time -> Timestamptz,
id -> Integer,
name -> Text,
latitude -> Numeric,
longitude -> Numeric,
}
}
(部分)Cargo.toml:
serde = "1.0.125"
serde_json = "1.0.64"
serde_derive = "1.0.125"
diesel = { version = "1.4.6", features = ["postgres", "r2d2", "chrono", "numeric"] }
bigdecimal = { version = "0.1.0", features = ["serde"] }
chrono = { version = "0.4.19", features = ["serde"] }
查询数据库的函数:
fn get_all_locations(pool: web::Data<Pool>) -> Result<Vec<Location>, diesel::result::Error> {
let conn = pool.get().unwrap();
let items = locations.load::<Location>(&conn)?;
Ok(items)
}
然后使用 serde_json 将其序列化为 JSON 数组。数据库中的 DateTime 是 2021-04-08 15:02:02.514+02
。当 DateTime 为 Utc 时,程序编译正常,但以 UTC 显示的 DateTime 类似于 2021-04-08T13:02:02.514Z
。我将 publication_time 更改为 DateTime<Local>
以保留时区信息,但 cargo build
失败并显示:
error[E0277]: the trait bound `DateTime<Local>: FromSql<diesel::sql_types::Timestamptz, Pg>` is not satisfied
--> src/controller.rs:21:27
|
21 | let items = locations.load::<Location>(&conn)?;
| ^^^^ the trait `FromSql<diesel::sql_types::Timestamptz, Pg>` is not implemented for `DateTime<Local>`
|
= help: the following implementations were found:
<DateTime<Utc> as FromSql<diesel::sql_types::Timestamptz, Pg>>
= note: required because of the requirements on the impl of `diesel::Queryable<diesel::sql_types::Timestamptz, Pg>` for `DateTime<Local>`
= note: 2 redundant requirements hidden
= note: required because of the requirements on the impl of `diesel::Queryable<(diesel::sql_types::Timestamptz, diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Numeric, diesel::sql_types::Numeric), Pg>` for `models::Location`
= note: required because of the requirements on the impl of `LoadQuery<_, models::Location>` for `locations::table`
我有另一个程序插入到这个 table 并且这个有效,唯一的区别是 derive(Deserialize, Insertable).
#[derive(Deserialize, Insertable)]
pub struct Location {
pub publication_time: DateTime<Local>,
pub id: i32,
pub name: String,
pub latitude: BigDecimal,
pub longitude: BigDecimal,
}
diesel 本身不支持将 Timestamptz
字段映射到 DateTime<Local>
,因为它只为 DateTime<Utc>
提供 the corresponding impl。
您可以通过在相应字段上使用 #[diesel(deserialize_as = "…")]
attribute 并提供您自己的反序列化包装器来解决此问题:
#[derive(Serialize, Queryable)]
pub struct Location {
#[diesel(deserialize_as = "MyDateTimeWrapper")]
pub publication_time: DateTime<Local>,
pub id: i32,
pub name: String,
pub latitude: BigDecimal,
pub longitude: BigDecimal,
}
pub struct MyDatetimeWrapper(DateTime<Local>);
impl Into<DateTime<Local>> for MyDatetimeWrapper {
fn into(self) -> DateTime<Local> {
self.0
}
}
impl<DB, ST> Queryable<ST, DB> for MyDateTimeWrapper
where
DB: Backend,
DateTime<Utc>: Queryable<ST, DB>,
{
type Row = <DateTime<Utc> as Queryable<ST, DB>>::Row;
fn build(row: Self::Row) -> Self {
Self(<DateTime<Utc> as Queryable<ST, DB>>::build(row).with_timezone(&Local))
}
}
我有一个 postgresql-table,其列定义为 timestamp with time zone
。 table 映射到此结构:
#[derive(Serialize, Queryable)]
pub struct Location {
pub publication_time: DateTime<Utc>,
pub id: i32,
pub name: String,
pub latitude: BigDecimal,
pub longitude: BigDecimal,
}
架构有这样的定义:
table! {
locations {
publication_time -> Timestamptz,
id -> Integer,
name -> Text,
latitude -> Numeric,
longitude -> Numeric,
}
}
(部分)Cargo.toml:
serde = "1.0.125"
serde_json = "1.0.64"
serde_derive = "1.0.125"
diesel = { version = "1.4.6", features = ["postgres", "r2d2", "chrono", "numeric"] }
bigdecimal = { version = "0.1.0", features = ["serde"] }
chrono = { version = "0.4.19", features = ["serde"] }
查询数据库的函数:
fn get_all_locations(pool: web::Data<Pool>) -> Result<Vec<Location>, diesel::result::Error> {
let conn = pool.get().unwrap();
let items = locations.load::<Location>(&conn)?;
Ok(items)
}
然后使用 serde_json 将其序列化为 JSON 数组。数据库中的 DateTime 是 2021-04-08 15:02:02.514+02
。当 DateTime 为 Utc 时,程序编译正常,但以 UTC 显示的 DateTime 类似于 2021-04-08T13:02:02.514Z
。我将 publication_time 更改为 DateTime<Local>
以保留时区信息,但 cargo build
失败并显示:
error[E0277]: the trait bound `DateTime<Local>: FromSql<diesel::sql_types::Timestamptz, Pg>` is not satisfied
--> src/controller.rs:21:27
|
21 | let items = locations.load::<Location>(&conn)?;
| ^^^^ the trait `FromSql<diesel::sql_types::Timestamptz, Pg>` is not implemented for `DateTime<Local>`
|
= help: the following implementations were found:
<DateTime<Utc> as FromSql<diesel::sql_types::Timestamptz, Pg>>
= note: required because of the requirements on the impl of `diesel::Queryable<diesel::sql_types::Timestamptz, Pg>` for `DateTime<Local>`
= note: 2 redundant requirements hidden
= note: required because of the requirements on the impl of `diesel::Queryable<(diesel::sql_types::Timestamptz, diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Numeric, diesel::sql_types::Numeric), Pg>` for `models::Location`
= note: required because of the requirements on the impl of `LoadQuery<_, models::Location>` for `locations::table`
我有另一个程序插入到这个 table 并且这个有效,唯一的区别是 derive(Deserialize, Insertable).
#[derive(Deserialize, Insertable)]
pub struct Location {
pub publication_time: DateTime<Local>,
pub id: i32,
pub name: String,
pub latitude: BigDecimal,
pub longitude: BigDecimal,
}
diesel 本身不支持将 Timestamptz
字段映射到 DateTime<Local>
,因为它只为 DateTime<Utc>
提供 the corresponding impl。
您可以通过在相应字段上使用 #[diesel(deserialize_as = "…")]
attribute 并提供您自己的反序列化包装器来解决此问题:
#[derive(Serialize, Queryable)]
pub struct Location {
#[diesel(deserialize_as = "MyDateTimeWrapper")]
pub publication_time: DateTime<Local>,
pub id: i32,
pub name: String,
pub latitude: BigDecimal,
pub longitude: BigDecimal,
}
pub struct MyDatetimeWrapper(DateTime<Local>);
impl Into<DateTime<Local>> for MyDatetimeWrapper {
fn into(self) -> DateTime<Local> {
self.0
}
}
impl<DB, ST> Queryable<ST, DB> for MyDateTimeWrapper
where
DB: Backend,
DateTime<Utc>: Queryable<ST, DB>,
{
type Row = <DateTime<Utc> as Queryable<ST, DB>>::Row;
fn build(row: Self::Row) -> Self {
Self(<DateTime<Utc> as Queryable<ST, DB>>::build(row).with_timezone(&Local))
}
}