vortex_array/extension/datetime/
time.rs1use std::fmt;
5
6use jiff::Span;
7use vortex_error::VortexExpect;
8use vortex_error::VortexResult;
9use vortex_error::vortex_bail;
10use vortex_error::vortex_ensure;
11use vortex_error::vortex_err;
12
13use crate::dtype::DType;
14use crate::dtype::Nullability;
15use crate::dtype::PType;
16use crate::dtype::extension::ExtDType;
17use crate::dtype::extension::ExtId;
18use crate::dtype::extension::ExtVTable;
19use crate::extension::datetime::TimeUnit;
20use crate::scalar::ScalarValue;
21
22#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
24pub struct Time;
25
26fn time_ptype(time_unit: &TimeUnit) -> Option<PType> {
27 Some(match time_unit {
28 TimeUnit::Nanoseconds | TimeUnit::Microseconds => PType::I64,
29 TimeUnit::Milliseconds | TimeUnit::Seconds => PType::I32,
30 TimeUnit::Days => return None,
31 })
32}
33
34impl Time {
35 pub fn try_new(time_unit: TimeUnit, nullability: Nullability) -> VortexResult<ExtDType<Self>> {
39 let ptype = time_ptype(&time_unit)
40 .ok_or_else(|| vortex_err!("Time type does not support time unit {}", time_unit))?;
41 ExtDType::try_new(time_unit, DType::Primitive(ptype, nullability))
42 }
43
44 pub fn new(time_unit: TimeUnit, nullability: Nullability) -> ExtDType<Self> {
46 Self::try_new(time_unit, nullability).vortex_expect("failed to create time dtype")
47 }
48}
49
50pub enum TimeValue {
52 Seconds(i32),
54 Milliseconds(i32),
56 Microseconds(i64),
58 Nanoseconds(i64),
60}
61
62impl fmt::Display for TimeValue {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 let min = jiff::civil::Time::MIN;
65
66 let time = match self {
67 TimeValue::Seconds(s) => min + Span::new().seconds(*s),
68 TimeValue::Milliseconds(ms) => min + Span::new().milliseconds(*ms),
69 TimeValue::Microseconds(us) => min + Span::new().microseconds(*us),
70 TimeValue::Nanoseconds(ns) => min + Span::new().nanoseconds(*ns),
71 };
72
73 write!(f, "{}", time)
74 }
75}
76
77impl ExtVTable for Time {
78 type Metadata = TimeUnit;
79
80 type NativeValue<'a> = TimeValue;
81
82 fn id(&self) -> ExtId {
83 ExtId::new_ref("vortex.time")
84 }
85
86 fn serialize_metadata(&self, metadata: &Self::Metadata) -> VortexResult<Vec<u8>> {
87 Ok(vec![u8::from(*metadata)])
88 }
89
90 fn deserialize_metadata(&self, data: &[u8]) -> VortexResult<Self::Metadata> {
91 let tag = data[0];
92 TimeUnit::try_from(tag)
93 }
94
95 fn validate_dtype(&self, metadata: &Self::Metadata, storage_dtype: &DType) -> VortexResult<()> {
96 let ptype = time_ptype(metadata)
97 .ok_or_else(|| vortex_err!("Time type does not support time unit {}", metadata))?;
98
99 vortex_ensure!(
100 storage_dtype.as_ptype() == ptype,
101 "Time storage dtype for {} must be {}",
102 metadata,
103 ptype
104 );
105
106 Ok(())
107 }
108
109 fn unpack_native(
110 &self,
111 metadata: &Self::Metadata,
112 _storage_dtype: &DType,
113 storage_value: &ScalarValue,
114 ) -> VortexResult<Self::NativeValue<'_>> {
115 let length_of_time = storage_value.as_primitive().cast::<i64>()?;
116
117 let (span, value) = match *metadata {
118 TimeUnit::Seconds => {
119 let v = i32::try_from(length_of_time)
120 .map_err(|e| vortex_err!("Time seconds value out of i32 range: {e}"))?;
121 (Span::new().seconds(v), TimeValue::Seconds(v))
122 }
123 TimeUnit::Milliseconds => {
124 let v = i32::try_from(length_of_time)
125 .map_err(|e| vortex_err!("Time milliseconds value out of i32 range: {e}"))?;
126 (Span::new().milliseconds(v), TimeValue::Milliseconds(v))
127 }
128 TimeUnit::Microseconds => (
129 Span::new().microseconds(length_of_time),
130 TimeValue::Microseconds(length_of_time),
131 ),
132 TimeUnit::Nanoseconds => (
133 Span::new().nanoseconds(length_of_time),
134 TimeValue::Nanoseconds(length_of_time),
135 ),
136 d @ TimeUnit::Days => vortex_bail!("Time type does not support time unit {d}"),
137 };
138
139 jiff::civil::Time::MIN
141 .checked_add(span)
142 .map_err(|e| vortex_err!("Invalid time scalar: {}", e))?;
143
144 Ok(value)
145 }
146}