mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-22 16:29:20 +08:00
commit
7def43fe7b
@ -1,7 +1,5 @@
|
||||
//! 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 crate::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
||||
@ -11,7 +9,7 @@ use crate::Result;
|
||||
impl ToSql for NaiveDate {
|
||||
#[inline]
|
||||
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))
|
||||
}
|
||||
}
|
||||
@ -22,7 +20,7 @@ impl FromSql for NaiveDate {
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||
value
|
||||
.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),
|
||||
Err(err) => Err(FromSqlError::Other(Box::new(err))),
|
||||
})
|
||||
@ -33,7 +31,7 @@ impl FromSql for NaiveDate {
|
||||
impl ToSql for NaiveTime {
|
||||
#[inline]
|
||||
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))
|
||||
}
|
||||
}
|
||||
@ -44,8 +42,8 @@ impl FromSql for NaiveTime {
|
||||
value.as_str().and_then(|s| {
|
||||
let fmt = match s.len() {
|
||||
5 => "%H:%M",
|
||||
8 => "%H:%M:%S",
|
||||
_ => "%H:%M:%S%.f",
|
||||
8 => "%T",
|
||||
_ => "%T%.f",
|
||||
};
|
||||
match NaiveTime::parse_from_str(s, fmt) {
|
||||
Ok(dt) => Ok(dt),
|
||||
@ -56,11 +54,11 @@ impl FromSql for NaiveTime {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
#[inline]
|
||||
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))
|
||||
}
|
||||
}
|
||||
@ -72,9 +70,9 @@ impl FromSql for NaiveDateTime {
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||
value.as_str().and_then(|s| {
|
||||
let fmt = if s.len() >= 11 && s.as_bytes()[10] == b'T' {
|
||||
"%Y-%m-%dT%H:%M:%S%.f"
|
||||
"%FT%T%.f"
|
||||
} else {
|
||||
"%Y-%m-%d %H:%M:%S%.f"
|
||||
"%F %T%.f"
|
||||
};
|
||||
|
||||
match NaiveDateTime::parse_from_str(s, fmt) {
|
||||
@ -86,34 +84,29 @@ impl FromSql for NaiveDateTime {
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
#[inline]
|
||||
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> {
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||
{
|
||||
// Try to parse value as rfc3339 first.
|
||||
let s = value.as_str()?;
|
||||
|
||||
// If timestamp looks space-separated, make a copy and replace it with 'T'.
|
||||
let s = if s.len() >= 11 && s.as_bytes()[10] == b' ' {
|
||||
let mut s = s.to_string();
|
||||
unsafe {
|
||||
let sbytes = s.as_mut_vec();
|
||||
sbytes[10] = b'T';
|
||||
}
|
||||
Cow::Owned(s)
|
||||
let fmt = if s.len() >= 11 && s.as_bytes()[10] == b'T' {
|
||||
"%FT%T%.f%:z"
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
@ -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> {
|
||||
#[inline]
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||
@ -179,7 +172,7 @@ mod test {
|
||||
db.execute("INSERT INTO foo (t) VALUES (?)", [dt])?;
|
||||
|
||||
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))?;
|
||||
assert_eq!(dt, v);
|
||||
|
||||
@ -200,7 +193,7 @@ mod test {
|
||||
db.execute("INSERT INTO foo (t) VALUES (?)", [utc])?;
|
||||
|
||||
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))?;
|
||||
assert_eq!(utc, v1);
|
||||
@ -252,4 +245,20 @@ mod test {
|
||||
assert!(result.is_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};
|
||||
|
||||
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";
|
||||
|
||||
impl ToSql for OffsetDateTime {
|
||||
@ -79,4 +79,12 @@ mod test {
|
||||
assert!(result.is_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