@@ -8,6 +8,7 @@ use std::collections::HashMap;
8
8
use std:: error:: Error ;
9
9
use std:: fmt;
10
10
use std:: sync:: Arc ;
11
+ use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
11
12
12
13
use types:: type_gen:: { Inner , Other } ;
13
14
@@ -16,6 +17,11 @@ pub use postgres_protocol::Oid;
16
17
17
18
pub use types:: special:: { Date , Timestamp } ;
18
19
20
+ // Number of seconds from 1970-01-01 to 2000-01-01
21
+ const TIME_SEC_CONVERSION : u64 = 946684800 ;
22
+ const USEC_PER_SEC : u64 = 1_000_000 ;
23
+ const NSEC_PER_USEC : u64 = 1_000 ;
24
+
19
25
/// Generates a simple implementation of `ToSql::accepts` which accepts the
20
26
/// types passed to it.
21
27
#[ macro_export]
@@ -252,6 +258,7 @@ impl WrongType {
252
258
/// | `&str`/`String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME, UNKNOWN |
253
259
/// | `&[u8]`/`Vec<u8>` | BYTEA |
254
260
/// | `HashMap<String, Option<String>>` | HSTORE |
261
+ /// | `SystemTime` | TIMESTAMP, TIMESTAMP WITH TIME ZONE |
255
262
///
256
263
/// In addition, some implementations are provided for types in third party
257
264
/// crates. These are disabled by default; to opt into one of these
@@ -449,6 +456,30 @@ impl<'a> FromSql<'a> for HashMap<String, Option<String>> {
449
456
}
450
457
}
451
458
459
+ impl < ' a > FromSql < ' a > for SystemTime {
460
+ fn from_sql ( _: & Type , raw : & ' a [ u8 ] ) -> Result < SystemTime , Box < Error + Sync + Send > > {
461
+ let time = types:: timestamp_from_sql ( raw) ?;
462
+ let epoch = UNIX_EPOCH + Duration :: from_secs ( TIME_SEC_CONVERSION ) ;
463
+
464
+ let negative = time < 0 ;
465
+ let time = time. abs ( ) as u64 ;
466
+
467
+ let secs = time / USEC_PER_SEC ;
468
+ let nsec = ( time % USEC_PER_SEC ) * NSEC_PER_USEC ;
469
+ let offset = Duration :: new ( secs, nsec as u32 ) ;
470
+
471
+ let time = if negative {
472
+ epoch - offset
473
+ } else {
474
+ epoch + offset
475
+ } ;
476
+
477
+ Ok ( time)
478
+ }
479
+
480
+ accepts ! ( TIMESTAMP , TIMESTAMPTZ ) ;
481
+ }
482
+
452
483
/// An enum representing the nullability of a Postgres value.
453
484
pub enum IsNull {
454
485
/// The value is NULL.
@@ -477,6 +508,7 @@ pub enum IsNull {
477
508
/// | `&str`/`String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME |
478
509
/// | `&[u8]`/Vec<u8>` | BYTEA |
479
510
/// | `HashMap<String, Option<String>>` | HSTORE |
511
+ /// | `SystemTime` | TIMESTAMP, TIMESTAMP WITH TIME ZONE |
480
512
///
481
513
/// In addition, some implementations are provided for types in third party
482
514
/// crates. These are disabled by default; to opt into one of these
@@ -724,6 +756,27 @@ impl ToSql for HashMap<String, Option<String>> {
724
756
to_sql_checked ! ( ) ;
725
757
}
726
758
759
+ impl ToSql for SystemTime {
760
+ fn to_sql ( & self , _: & Type , w : & mut Vec < u8 > ) -> Result < IsNull , Box < Error + Sync + Send > > {
761
+ let epoch = UNIX_EPOCH + Duration :: from_secs ( TIME_SEC_CONVERSION ) ;
762
+
763
+ let to_usec =
764
+ |d : Duration | d. as_secs ( ) * USEC_PER_SEC + ( d. subsec_nanos ( ) as u64 ) / NSEC_PER_USEC ;
765
+
766
+ let time = match self . duration_since ( epoch) {
767
+ Ok ( duration) => to_usec ( duration) as i64 ,
768
+ Err ( e) => -( to_usec ( e. duration ( ) ) as i64 ) ,
769
+ } ;
770
+
771
+ types:: timestamp_to_sql ( time, w) ;
772
+ Ok ( IsNull :: No )
773
+ }
774
+
775
+ accepts ! ( TIMESTAMP , TIMESTAMPTZ ) ;
776
+
777
+ to_sql_checked ! ( ) ;
778
+ }
779
+
727
780
fn downcast ( len : usize ) -> Result < i32 , Box < Error + Sync + Send > > {
728
781
if len > i32:: max_value ( ) as usize {
729
782
Err ( "value too large to transmit" . into ( ) )
0 commit comments