pgx/datum/
time_with_timezone.rs1use crate::datum::time::{Time, USECS_PER_DAY};
11use crate::{pg_sys, FromDatum, IntoDatum, PgBox};
12use pgx_sql_entity_graph::metadata::{
13 ArgumentError, Returns, ReturnsError, SqlMapping, SqlTranslatable,
14};
15
16#[derive(Debug, Clone)]
17#[repr(C)]
18pub struct TimeWithTimeZone {
19 t: Time,
20 tz_secs: i32,
24}
25
26impl FromDatum for TimeWithTimeZone {
27 #[inline]
28 unsafe fn from_polymorphic_datum(
29 datum: pg_sys::Datum,
30 is_null: bool,
31 typoid: pg_sys::Oid,
32 ) -> Option<TimeWithTimeZone> {
33 if is_null {
34 None
35 } else {
36 let timetz = PgBox::from_pg(datum.cast_mut_ptr::<pg_sys::TimeTzADT>());
37
38 let t = Time::from_polymorphic_datum(timetz.time.into(), false, typoid)
39 .expect("failed to convert TimeWithTimeZone");
40 let tz_secs = timetz.zone;
41
42 Some(TimeWithTimeZone { t, tz_secs })
43 }
44 }
45}
46
47impl IntoDatum for TimeWithTimeZone {
48 #[inline]
49 fn into_datum(self) -> Option<pg_sys::Datum> {
50 let mut timetz = unsafe { PgBox::<pg_sys::TimeTzADT>::alloc() };
51 timetz.zone = self.tz_secs;
52 timetz.time = self.t.0 as i64;
53
54 Some(timetz.into_pg().into())
55 }
56
57 fn type_oid() -> pg_sys::Oid {
58 pg_sys::TIMETZOID
59 }
60}
61
62impl TimeWithTimeZone {
63 #[deprecated(
65 since = "0.5.0",
66 note = "the repr of pgx::TimeWithTimeZone is no longer time::Time \
67 and this fn will be removed in a future version"
68 )]
69 #[cfg(feature = "time-crate")]
70 pub fn new(time: time::Time, at_tz_offset: time::UtcOffset) -> Self {
71 let (h, m, s, micro) = time.as_hms_micro();
72 let t = Time::from_hms_micro(h, m, s, micro).unwrap();
73 let tz_secs = -at_tz_offset.whole_seconds();
75 TimeWithTimeZone { t, tz_secs }
76 }
77
78 pub fn to_utc(self) -> Time {
79 let TimeWithTimeZone { t, tz_secs } = self;
80 let tz_micros = tz_secs as i64 * 1_000_000;
81 let t_unwrapped = t.0 as i64 + tz_micros;
83 Time(t_unwrapped.rem_euclid(USECS_PER_DAY as i64) as u64)
84 }
85}
86
87impl From<Time> for TimeWithTimeZone {
88 fn from(t: Time) -> TimeWithTimeZone {
89 TimeWithTimeZone { t, tz_secs: 0 }
90 }
91}
92
93impl serde::Serialize for TimeWithTimeZone {
94 fn serialize<S>(
95 &self,
96 serializer: S,
97 ) -> std::result::Result<<S as serde::Serializer>::Ok, <S as serde::Serializer>::Error>
98 where
99 S: serde::Serializer,
100 {
101 let cstr: Option<&core::ffi::CStr> = unsafe {
102 crate::direct_function_call(
103 pg_sys::timetz_out,
104 vec![Some(pg_sys::Datum::from(self as *const Self))],
105 )
106 };
107 serializer.serialize_str(cstr.and_then(|c| c.to_str().ok()).unwrap())
108 }
109}
110
111unsafe impl SqlTranslatable for TimeWithTimeZone {
112 fn argument_sql() -> Result<SqlMapping, ArgumentError> {
113 Ok(SqlMapping::literal("time with time zone"))
114 }
115 fn return_sql() -> Result<Returns, ReturnsError> {
116 Ok(Returns::One(SqlMapping::literal("time with time zone")))
117 }
118}