1use crate::ArrowPrimitiveType;
21use crate::timezone::Tz;
22use arrow_schema::{DataType, TimeUnit};
23use chrono::{DateTime, Duration, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Timelike, Utc};
24
25pub const SECONDS_IN_DAY: i64 = 86_400;
27pub const MILLISECONDS: i64 = 1_000;
29pub const MICROSECONDS: i64 = 1_000_000;
31pub const NANOSECONDS: i64 = 1_000_000_000;
33
34pub const MILLISECONDS_IN_DAY: i64 = SECONDS_IN_DAY * MILLISECONDS;
36pub const MICROSECONDS_IN_DAY: i64 = SECONDS_IN_DAY * MICROSECONDS;
38pub const NANOSECONDS_IN_DAY: i64 = SECONDS_IN_DAY * NANOSECONDS;
40
41pub const UNIX_EPOCH_DAY: i64 = 719_163;
52
53#[inline]
55pub fn date32_to_datetime(v: i32) -> Option<NaiveDateTime> {
56 Some(DateTime::from_timestamp(v as i64 * SECONDS_IN_DAY, 0)?.naive_utc())
57}
58
59#[inline]
61pub fn date64_to_datetime(v: i64) -> Option<NaiveDateTime> {
62 let (sec, milli_sec) = split_second(v, MILLISECONDS);
63
64 let datetime = DateTime::from_timestamp(
65 sec,
67 milli_sec * MICROSECONDS as u32,
69 )?;
70 Some(datetime.naive_utc())
71}
72
73#[inline]
75pub fn time32s_to_time(v: i32) -> Option<NaiveTime> {
76 NaiveTime::from_num_seconds_from_midnight_opt(v as u32, 0)
77}
78
79#[inline]
81pub fn time32ms_to_time(v: i32) -> Option<NaiveTime> {
82 let v = v as i64;
83 NaiveTime::from_num_seconds_from_midnight_opt(
84 (v / MILLISECONDS) as u32,
86 (v % MILLISECONDS * MICROSECONDS) as u32,
89 )
90}
91
92#[inline]
94pub fn time64us_to_time(v: i64) -> Option<NaiveTime> {
95 NaiveTime::from_num_seconds_from_midnight_opt(
96 (v / MICROSECONDS) as u32,
98 (v % MICROSECONDS * MILLISECONDS) as u32,
101 )
102}
103
104#[inline]
106pub fn time64ns_to_time(v: i64) -> Option<NaiveTime> {
107 NaiveTime::from_num_seconds_from_midnight_opt(
108 (v / NANOSECONDS) as u32,
110 (v % NANOSECONDS) as u32,
112 )
113}
114
115#[inline]
117pub fn time_to_time32s(v: NaiveTime) -> i32 {
118 v.num_seconds_from_midnight() as i32
119}
120
121#[inline]
123pub fn time_to_time32ms(v: NaiveTime) -> i32 {
124 (v.num_seconds_from_midnight() as i64 * MILLISECONDS
125 + v.nanosecond() as i64 * MILLISECONDS / NANOSECONDS) as i32
126}
127
128#[inline]
130pub fn time_to_time64us(v: NaiveTime) -> i64 {
131 v.num_seconds_from_midnight() as i64 * MICROSECONDS
132 + v.nanosecond() as i64 * MICROSECONDS / NANOSECONDS
133}
134
135#[inline]
137pub fn time_to_time64ns(v: NaiveTime) -> i64 {
138 v.num_seconds_from_midnight() as i64 * NANOSECONDS + v.nanosecond() as i64
139}
140
141#[inline]
143pub fn timestamp_s_to_datetime(v: i64) -> Option<NaiveDateTime> {
144 Some(DateTime::from_timestamp(v, 0)?.naive_utc())
145}
146
147#[inline]
149pub fn timestamp_s_to_date(secs: i64) -> Option<NaiveDateTime> {
150 let days = secs.div_euclid(86_400) + UNIX_EPOCH_DAY;
151 if days < i32::MIN as i64 || days > i32::MAX as i64 {
152 return None;
153 }
154 let date = NaiveDate::from_num_days_from_ce_opt(days as i32)?;
155 Some(date.and_time(NaiveTime::default()).and_utc().naive_utc())
156}
157
158#[inline]
160pub fn timestamp_s_to_time(secs: i64) -> Option<NaiveDateTime> {
161 let secs = secs.rem_euclid(86_400);
162 let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, 0)?;
163 Some(
164 DateTime::<Utc>::from_naive_utc_and_offset(
165 NaiveDateTime::new(NaiveDate::default(), time),
166 Utc,
167 )
168 .naive_utc(),
169 )
170}
171
172#[inline]
174pub fn timestamp_ms_to_datetime(v: i64) -> Option<NaiveDateTime> {
175 let (sec, milli_sec) = split_second(v, MILLISECONDS);
176
177 let datetime = DateTime::from_timestamp(
178 sec,
180 milli_sec * MICROSECONDS as u32,
182 )?;
183 Some(datetime.naive_utc())
184}
185
186#[inline]
188pub fn timestamp_us_to_datetime(v: i64) -> Option<NaiveDateTime> {
189 let (sec, micro_sec) = split_second(v, MICROSECONDS);
190
191 let datetime = DateTime::from_timestamp(
192 sec,
194 micro_sec * MILLISECONDS as u32,
196 )?;
197 Some(datetime.naive_utc())
198}
199
200#[inline]
202pub fn timestamp_ns_to_datetime(v: i64) -> Option<NaiveDateTime> {
203 let (sec, nano_sec) = split_second(v, NANOSECONDS);
204
205 let datetime = DateTime::from_timestamp(
206 sec, nano_sec,
209 )?;
210 Some(datetime.naive_utc())
211}
212
213#[inline]
214pub(crate) fn split_second(v: i64, base: i64) -> (i64, u32) {
215 (v.div_euclid(base), v.rem_euclid(base) as u32)
216}
217
218#[inline]
220pub fn try_duration_s_to_duration(v: i64) -> Option<Duration> {
221 Duration::try_seconds(v)
222}
223
224#[inline]
226pub fn try_duration_ms_to_duration(v: i64) -> Option<Duration> {
227 Duration::try_milliseconds(v)
228}
229
230#[inline]
232pub fn duration_us_to_duration(v: i64) -> Duration {
233 Duration::microseconds(v)
234}
235
236#[inline]
238pub fn duration_ns_to_duration(v: i64) -> Duration {
239 Duration::nanoseconds(v)
240}
241
242pub fn as_datetime<T: ArrowPrimitiveType>(v: i64) -> Option<NaiveDateTime> {
244 as_datetime_with_data_type(&T::DATA_TYPE, v)
245}
246
247#[inline]
253pub(crate) fn as_datetime_with_data_type(data_type: &DataType, v: i64) -> Option<NaiveDateTime> {
254 match data_type {
255 DataType::Date32 => date32_to_datetime(v as i32),
256 DataType::Date64 => date64_to_datetime(v),
257 DataType::Time32(_) | DataType::Time64(_) => None,
258 DataType::Timestamp(unit, _) => match unit {
259 TimeUnit::Second => timestamp_s_to_datetime(v),
260 TimeUnit::Millisecond => timestamp_ms_to_datetime(v),
261 TimeUnit::Microsecond => timestamp_us_to_datetime(v),
262 TimeUnit::Nanosecond => timestamp_ns_to_datetime(v),
263 },
264 DataType::Interval(_) => None,
266 _ => None,
267 }
268}
269
270pub fn as_datetime_with_timezone<T: ArrowPrimitiveType>(v: i64, tz: Tz) -> Option<DateTime<Tz>> {
272 as_datetime_with_timezone_and_data_type(&T::DATA_TYPE, v, tz)
273}
274
275#[inline]
280pub(crate) fn as_datetime_with_timezone_and_data_type(
281 data_type: &DataType,
282 v: i64,
283 tz: Tz,
284) -> Option<DateTime<Tz>> {
285 let naive = as_datetime_with_data_type(data_type, v)?;
286 Some(Utc.from_utc_datetime(&naive).with_timezone(&tz))
287}
288
289pub fn as_date<T: ArrowPrimitiveType>(v: i64) -> Option<NaiveDate> {
291 as_datetime::<T>(v).map(|datetime| datetime.date())
292}
293
294pub fn as_time<T: ArrowPrimitiveType>(v: i64) -> Option<NaiveTime> {
296 as_time_with_data_type(&T::DATA_TYPE, v)
297}
298
299#[inline]
303pub(crate) fn as_time_with_data_type(data_type: &DataType, v: i64) -> Option<NaiveTime> {
304 match data_type {
305 DataType::Time32(unit) => {
306 let v = v as u32;
308 match unit {
309 TimeUnit::Second => time32s_to_time(v as i32),
310 TimeUnit::Millisecond => time32ms_to_time(v as i32),
311 _ => None,
312 }
313 }
314 DataType::Time64(unit) => match unit {
315 TimeUnit::Microsecond => time64us_to_time(v),
316 TimeUnit::Nanosecond => time64ns_to_time(v),
317 _ => None,
318 },
319 DataType::Timestamp(_, _) => {
320 as_datetime_with_data_type(data_type, v).map(|datetime| datetime.time())
321 }
322 DataType::Date32 | DataType::Date64 => NaiveTime::from_hms_opt(0, 0, 0),
323 DataType::Interval(_) => None,
324 _ => None,
325 }
326}
327
328pub fn as_duration<T: ArrowPrimitiveType>(v: i64) -> Option<Duration> {
330 match T::DATA_TYPE {
331 DataType::Duration(unit) => match unit {
332 TimeUnit::Second => try_duration_s_to_duration(v),
333 TimeUnit::Millisecond => try_duration_ms_to_duration(v),
334 TimeUnit::Microsecond => Some(duration_us_to_duration(v)),
335 TimeUnit::Nanosecond => Some(duration_ns_to_duration(v)),
336 },
337 _ => None,
338 }
339}
340
341#[cfg(test)]
342mod tests {
343 use crate::temporal_conversions::{
344 NANOSECONDS, date64_to_datetime, split_second, timestamp_ms_to_datetime,
345 timestamp_ns_to_datetime, timestamp_s_to_date, timestamp_s_to_datetime,
346 timestamp_s_to_time, timestamp_us_to_datetime,
347 };
348 use chrono::DateTime;
349
350 #[test]
351 fn test_timestamp_func() {
352 let timestamp = 1234;
353 let datetime = timestamp_s_to_datetime(timestamp).unwrap();
354 let expected_date = datetime.date();
355 let expected_time = datetime.time();
356
357 assert_eq!(
358 timestamp_s_to_date(timestamp).unwrap().date(),
359 expected_date
360 );
361 assert_eq!(
362 timestamp_s_to_time(timestamp).unwrap().time(),
363 expected_time
364 );
365 }
366
367 #[test]
368 fn negative_input_timestamp_ns_to_datetime() {
369 assert_eq!(
370 timestamp_ns_to_datetime(-1),
371 DateTime::from_timestamp(-1, 999_999_999).map(|x| x.naive_utc())
372 );
373
374 assert_eq!(
375 timestamp_ns_to_datetime(-1_000_000_001),
376 DateTime::from_timestamp(-2, 999_999_999).map(|x| x.naive_utc())
377 );
378 }
379
380 #[test]
381 fn negative_input_timestamp_us_to_datetime() {
382 assert_eq!(
383 timestamp_us_to_datetime(-1),
384 DateTime::from_timestamp(-1, 999_999_000).map(|x| x.naive_utc())
385 );
386
387 assert_eq!(
388 timestamp_us_to_datetime(-1_000_001),
389 DateTime::from_timestamp(-2, 999_999_000).map(|x| x.naive_utc())
390 );
391 }
392
393 #[test]
394 fn negative_input_timestamp_ms_to_datetime() {
395 assert_eq!(
396 timestamp_ms_to_datetime(-1),
397 DateTime::from_timestamp(-1, 999_000_000).map(|x| x.naive_utc())
398 );
399
400 assert_eq!(
401 timestamp_ms_to_datetime(-1_001),
402 DateTime::from_timestamp(-2, 999_000_000).map(|x| x.naive_utc())
403 );
404 }
405
406 #[test]
407 fn negative_input_date64_to_datetime() {
408 assert_eq!(
409 date64_to_datetime(-1),
410 DateTime::from_timestamp(-1, 999_000_000).map(|x| x.naive_utc())
411 );
412
413 assert_eq!(
414 date64_to_datetime(-1_001),
415 DateTime::from_timestamp(-2, 999_000_000).map(|x| x.naive_utc())
416 );
417 }
418
419 #[test]
420 fn test_split_seconds() {
421 let (sec, nano_sec) = split_second(100, NANOSECONDS);
422 assert_eq!(sec, 0);
423 assert_eq!(nano_sec, 100);
424
425 let (sec, nano_sec) = split_second(123_000_000_456, NANOSECONDS);
426 assert_eq!(sec, 123);
427 assert_eq!(nano_sec, 456);
428
429 let (sec, nano_sec) = split_second(-1, NANOSECONDS);
430 assert_eq!(sec, -1);
431 assert_eq!(nano_sec, 999_999_999);
432
433 let (sec, nano_sec) = split_second(-123_000_000_001, NANOSECONDS);
434 assert_eq!(sec, -124);
435 assert_eq!(nano_sec, 999_999_999);
436 }
437}