diff --git a/src/sql_type/chrono.rs b/src/sql_type/chrono.rs index e1fbc0ed..3006afc6 100644 --- a/src/sql_type/chrono.rs +++ b/src/sql_type/chrono.rs @@ -64,14 +64,24 @@ where impl FromSql for DateTime { fn from_sql(val: &SqlValue) -> Result> { let ts = val.to_timestamp()?; - datetime_from_sql(&Utc, &ts) + if ts.with_tz() { + datetime_from_sql(&fixed_offset_from_sql(&ts)?, &ts) + .map(|val| val.with_timezone(&Utc)) + } else { + datetime_from_sql(&Utc, &ts) + } } } impl FromSql for DateTime { fn from_sql(val: &SqlValue) -> Result> { let ts = val.to_timestamp()?; - datetime_from_sql(&Local, &ts) + if ts.with_tz() { + datetime_from_sql(&fixed_offset_from_sql(&ts)?, &ts) + .map(|val| val.with_timezone(&Local)) + } else { + datetime_from_sql(&Local, &ts) + } } } @@ -144,7 +154,12 @@ where impl FromSql for Date { fn from_sql(val: &SqlValue) -> Result> { let ts = val.to_timestamp()?; - date_from_sql(&Utc, &ts) + if ts.with_tz() { + date_from_sql(&fixed_offset_from_sql(&ts)?, &ts) + .map(|val| val.with_timezone(&Utc)) + } else { + date_from_sql(&Utc, &ts) + } } } @@ -152,7 +167,12 @@ impl FromSql for Date { impl FromSql for Date { fn from_sql(val: &SqlValue) -> Result> { let ts = val.to_timestamp()?; - date_from_sql(&Local, &ts) + if ts.with_tz() { + date_from_sql(&fixed_offset_from_sql(&ts)?, &ts) + .map(|val| val.with_timezone(&Local)) + } else { + date_from_sql(&Local, &ts) + } } } diff --git a/tests/from_to_sql.rs b/tests/from_to_sql.rs index 98dafec7..880a393d 100644 --- a/tests/from_to_sql.rs +++ b/tests/from_to_sql.rs @@ -887,17 +887,27 @@ mod chrono { &dttm ); - // TIMESTAMP WITH TIME ZONE -> DateTime TZ is ignored. - let dttm = Utc.ymd(2012, 3, 4).and_hms_nano(5, 6, 7, 123456789); + // TIMESTAMP WITH TIME ZONE -> DateTime TZ is mapped. + let dttm = Utc.ymd(2012, 3, 4).and_hms_nano(4, 6, 7, 123456789); test_from_sql!(&conn, "TO_TIMESTAMP_TZ('2012-03-04 05:06:07.123456789 +01:00', 'YYYY-MM-DD HH24:MI:SS.FF9 TZH:TZM')", &OracleType::TimestampTZ(9), &dttm); - // TIMESTAMP WITH TIME ZONE -> DateTime TZ is ignored. + // TIMESTAMP WITH TIME ZONE -> DateTime TZ is mapped. let dttm = Local.ymd(2012, 3, 4).and_hms_nano(5, 6, 7, 123456789); - test_from_sql!(&conn, - "TO_TIMESTAMP_TZ('2012-03-04 05:06:07.123456789 +01:00', 'YYYY-MM-DD HH24:MI:SS.FF9 TZH:TZM')", - &OracleType::TimestampTZ(9), &dttm); + let tz_offset = dttm.offset().fix().local_minus_utc(); + let tz_sign = if tz_offset >= 0 { '+' } else { '-' }; + let tz_hour = tz_offset.abs() / 3600; + let tz_min = tz_offset.abs() % 3600 / 60; + test_from_sql!( + &conn, + &format!( + "TO_TIMESTAMP_TZ('2012-03-04 05:06:07.123456789 {}{:02}:{:02}', 'YYYY-MM-DD HH24:MI:SS.FF9 TZH:TZM')", + tz_sign, tz_hour, tz_min + ), + &OracleType::TimestampTZ(9), + &dttm + ); // TIMESTAMP WITH TIME ZONE -> DateTime TZ is set. let dttm = fixed_cet.ymd(2012, 3, 4).and_hms_nano(5, 6, 7, 123456789); @@ -1015,13 +1025,13 @@ mod chrono { &dttm ); - // TIMESTAMP WITH TIME ZONE -> Date TZ is ignored. + // TIMESTAMP WITH TIME ZONE -> Date TZ is mapped. let dttm = Utc.ymd(2012, 3, 4); test_from_sql!(&conn, "TO_TIMESTAMP_TZ('2012-03-04 05:06:07.123456789 +01:00', 'YYYY-MM-DD HH24:MI:SS.FF9 TZH:TZM')", &OracleType::TimestampTZ(9), &dttm); - // TIMESTAMP WITH TIME ZONE -> Date TZ is ignored. + // TIMESTAMP WITH TIME ZONE -> Date TZ is mapped. let dttm = Local.ymd(2012, 3, 4); test_from_sql!(&conn, "TO_TIMESTAMP_TZ('2012-03-04 05:06:07.123456789 +01:00', 'YYYY-MM-DD HH24:MI:SS.FF9 TZH:TZM')",