mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-27 03:51:38 +08:00
commit
7def43fe7b
@ -1,7 +1,5 @@
|
|||||||
//! Convert most of the [Time Strings](http://sqlite.org/lang_datefunc.html) to chrono types.
|
//! Convert most of the [Time Strings](http://sqlite.org/lang_datefunc.html) to chrono types.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
|
use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
|
||||||
|
|
||||||
use crate::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
use crate::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
||||||
@ -11,7 +9,7 @@ use crate::Result;
|
|||||||
impl ToSql for NaiveDate {
|
impl ToSql for NaiveDate {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
||||||
let date_str = self.format("%Y-%m-%d").to_string();
|
let date_str = self.format("%F").to_string();
|
||||||
Ok(ToSqlOutput::from(date_str))
|
Ok(ToSqlOutput::from(date_str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22,7 +20,7 @@ impl FromSql for NaiveDate {
|
|||||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
value
|
value
|
||||||
.as_str()
|
.as_str()
|
||||||
.and_then(|s| match NaiveDate::parse_from_str(s, "%Y-%m-%d") {
|
.and_then(|s| match NaiveDate::parse_from_str(s, "%F") {
|
||||||
Ok(dt) => Ok(dt),
|
Ok(dt) => Ok(dt),
|
||||||
Err(err) => Err(FromSqlError::Other(Box::new(err))),
|
Err(err) => Err(FromSqlError::Other(Box::new(err))),
|
||||||
})
|
})
|
||||||
@ -33,7 +31,7 @@ impl FromSql for NaiveDate {
|
|||||||
impl ToSql for NaiveTime {
|
impl ToSql for NaiveTime {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
||||||
let date_str = self.format("%H:%M:%S%.f").to_string();
|
let date_str = self.format("%T%.f").to_string();
|
||||||
Ok(ToSqlOutput::from(date_str))
|
Ok(ToSqlOutput::from(date_str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,8 +42,8 @@ impl FromSql for NaiveTime {
|
|||||||
value.as_str().and_then(|s| {
|
value.as_str().and_then(|s| {
|
||||||
let fmt = match s.len() {
|
let fmt = match s.len() {
|
||||||
5 => "%H:%M",
|
5 => "%H:%M",
|
||||||
8 => "%H:%M:%S",
|
8 => "%T",
|
||||||
_ => "%H:%M:%S%.f",
|
_ => "%T%.f",
|
||||||
};
|
};
|
||||||
match NaiveTime::parse_from_str(s, fmt) {
|
match NaiveTime::parse_from_str(s, fmt) {
|
||||||
Ok(dt) => Ok(dt),
|
Ok(dt) => Ok(dt),
|
||||||
@ -56,11 +54,11 @@ impl FromSql for NaiveTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ISO 8601 combined date and time without timezone =>
|
/// ISO 8601 combined date and time without timezone =>
|
||||||
/// "YYYY-MM-DDTHH:MM:SS.SSS"
|
/// "YYYY-MM-DD HH:MM:SS.SSS"
|
||||||
impl ToSql for NaiveDateTime {
|
impl ToSql for NaiveDateTime {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
||||||
let date_str = self.format("%Y-%m-%dT%H:%M:%S%.f").to_string();
|
let date_str = self.format("%F %T%.f").to_string();
|
||||||
Ok(ToSqlOutput::from(date_str))
|
Ok(ToSqlOutput::from(date_str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,9 +70,9 @@ impl FromSql for NaiveDateTime {
|
|||||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
value.as_str().and_then(|s| {
|
value.as_str().and_then(|s| {
|
||||||
let fmt = if s.len() >= 11 && s.as_bytes()[10] == b'T' {
|
let fmt = if s.len() >= 11 && s.as_bytes()[10] == b'T' {
|
||||||
"%Y-%m-%dT%H:%M:%S%.f"
|
"%FT%T%.f"
|
||||||
} else {
|
} else {
|
||||||
"%Y-%m-%d %H:%M:%S%.f"
|
"%F %T%.f"
|
||||||
};
|
};
|
||||||
|
|
||||||
match NaiveDateTime::parse_from_str(s, fmt) {
|
match NaiveDateTime::parse_from_str(s, fmt) {
|
||||||
@ -86,34 +84,29 @@ impl FromSql for NaiveDateTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Date and time with time zone => UTC RFC3339 timestamp
|
/// Date and time with time zone => UTC RFC3339 timestamp
|
||||||
/// ("YYYY-MM-DDTHH:MM:SS.SSS+00:00").
|
/// ("YYYY-MM-DD HH:MM:SS.SSS+00:00").
|
||||||
impl<Tz: TimeZone> ToSql for DateTime<Tz> {
|
impl<Tz: TimeZone> ToSql for DateTime<Tz> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
||||||
Ok(ToSqlOutput::from(self.with_timezone(&Utc).to_rfc3339()))
|
let date_str = self.with_timezone(&Utc).format("%F %T%.f%:z").to_string();
|
||||||
|
Ok(ToSqlOutput::from(date_str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into `DateTime<Utc>`.
|
/// RFC3339 ("YYYY-MM-DD HH:MM:SS.SSS[+-]HH:MM") into `DateTime<Utc>`.
|
||||||
impl FromSql for DateTime<Utc> {
|
impl FromSql for DateTime<Utc> {
|
||||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
{
|
{
|
||||||
// Try to parse value as rfc3339 first.
|
// Try to parse value as rfc3339 first.
|
||||||
let s = value.as_str()?;
|
let s = value.as_str()?;
|
||||||
|
|
||||||
// If timestamp looks space-separated, make a copy and replace it with 'T'.
|
let fmt = if s.len() >= 11 && s.as_bytes()[10] == b'T' {
|
||||||
let s = if s.len() >= 11 && s.as_bytes()[10] == b' ' {
|
"%FT%T%.f%:z"
|
||||||
let mut s = s.to_string();
|
|
||||||
unsafe {
|
|
||||||
let sbytes = s.as_mut_vec();
|
|
||||||
sbytes[10] = b'T';
|
|
||||||
}
|
|
||||||
Cow::Owned(s)
|
|
||||||
} else {
|
} else {
|
||||||
Cow::Borrowed(s)
|
"%F %T%.f%:z"
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(dt) = DateTime::parse_from_rfc3339(&s) {
|
if let Ok(dt) = DateTime::parse_from_str(s, fmt) {
|
||||||
return Ok(dt.with_timezone(&Utc));
|
return Ok(dt.with_timezone(&Utc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +116,7 @@ impl FromSql for DateTime<Utc> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into `DateTime<Local>`.
|
/// RFC3339 ("YYYY-MM-DD HH:MM:SS.SSS[+-]HH:MM") into `DateTime<Local>`.
|
||||||
impl FromSql for DateTime<Local> {
|
impl FromSql for DateTime<Local> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
@ -179,7 +172,7 @@ mod test {
|
|||||||
db.execute("INSERT INTO foo (t) VALUES (?)", [dt])?;
|
db.execute("INSERT INTO foo (t) VALUES (?)", [dt])?;
|
||||||
|
|
||||||
let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
|
let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
|
||||||
assert_eq!("2016-02-23T23:56:04", s);
|
assert_eq!("2016-02-23 23:56:04", s);
|
||||||
let v: NaiveDateTime = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
|
let v: NaiveDateTime = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
|
||||||
assert_eq!(dt, v);
|
assert_eq!(dt, v);
|
||||||
|
|
||||||
@ -200,7 +193,7 @@ mod test {
|
|||||||
db.execute("INSERT INTO foo (t) VALUES (?)", [utc])?;
|
db.execute("INSERT INTO foo (t) VALUES (?)", [utc])?;
|
||||||
|
|
||||||
let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
|
let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
|
||||||
assert_eq!("2016-02-23T23:56:04.789+00:00", s);
|
assert_eq!("2016-02-23 23:56:04.789+00:00", s);
|
||||||
|
|
||||||
let v1: DateTime<Utc> = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
|
let v1: DateTime<Utc> = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
|
||||||
assert_eq!(utc, v1);
|
assert_eq!(utc, v1);
|
||||||
@ -252,4 +245,20 @@ mod test {
|
|||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_naive_date_time_param() -> Result<()> {
|
||||||
|
let db = checked_memory_handle()?;
|
||||||
|
let result: Result<bool> = db.query_row("SELECT 1 WHERE ? BETWEEN datetime('now', '-1 seconds') AND datetime('now', '+1 seconds')", [Utc::now().naive_utc()], |r| r.get(0));
|
||||||
|
assert!(result.is_ok());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_date_time_param() -> Result<()> {
|
||||||
|
let db = checked_memory_handle()?;
|
||||||
|
let result: Result<bool> = db.query_row("SELECT 1 WHERE ? BETWEEN datetime('now', '-1 seconds') AND datetime('now', '+1 seconds')", [Utc::now()], |r| r.get(0));
|
||||||
|
assert!(result.is_ok());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use crate::Result;
|
|||||||
use time::{OffsetDateTime, PrimitiveDateTime, UtcOffset};
|
use time::{OffsetDateTime, PrimitiveDateTime, UtcOffset};
|
||||||
|
|
||||||
const CURRENT_TIMESTAMP_FMT: &str = "%Y-%m-%d %H:%M:%S";
|
const CURRENT_TIMESTAMP_FMT: &str = "%Y-%m-%d %H:%M:%S";
|
||||||
const SQLITE_DATETIME_FMT: &str = "%Y-%m-%dT%H:%M:%S.%NZ";
|
const SQLITE_DATETIME_FMT: &str = "%Y-%m-%d %H:%M:%S.%NZ";
|
||||||
const SQLITE_DATETIME_FMT_LEGACY: &str = "%Y-%m-%d %H:%M:%S:%N %z";
|
const SQLITE_DATETIME_FMT_LEGACY: &str = "%Y-%m-%d %H:%M:%S:%N %z";
|
||||||
|
|
||||||
impl ToSql for OffsetDateTime {
|
impl ToSql for OffsetDateTime {
|
||||||
@ -79,4 +79,12 @@ mod test {
|
|||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_param() -> Result<()> {
|
||||||
|
let db = checked_memory_handle()?;
|
||||||
|
let result: Result<bool> = db.query_row("SELECT 1 WHERE ? BETWEEN datetime('now', '-1 seconds') AND datetime('now', '+1 seconds')", [OffsetDateTime::now_utc()], |r| r.get(0));
|
||||||
|
assert!(result.is_ok());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user