1use crate::timezone::Tz;
21use crate::ArrowPrimitiveType;
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]
220#[deprecated(since = "55.2.0", note = "Use `try_duration_s_to_duration` instead")]
221pub fn duration_s_to_duration(v: i64) -> Duration {
222 Duration::try_seconds(v).unwrap()
223}
224
225#[inline]
227pub fn try_duration_s_to_duration(v: i64) -> Option<Duration> {
228 Duration::try_seconds(v)
229}
230
231#[inline]
233#[deprecated(since = "55.2.0", note = "Use `try_duration_ms_to_duration` instead")]
234pub fn duration_ms_to_duration(v: i64) -> Duration {
235 Duration::try_seconds(v).unwrap()
236}
237
238#[inline]
240pub fn try_duration_ms_to_duration(v: i64) -> Option<Duration> {
241 Duration::try_milliseconds(v)
242}
243
244#[inline]
246pub fn duration_us_to_duration(v: i64) -> Duration {
247 Duration::microseconds(v)
248}
249
250#[inline]
252pub fn duration_ns_to_duration(v: i64) -> Duration {
253 Duration::nanoseconds(v)
254}
255
256pub fn as_datetime<T: ArrowPrimitiveType>(v: i64) -> Option<NaiveDateTime> {
258 match T::DATA_TYPE {
259 DataType::Date32 => date32_to_datetime(v as i32),
260 DataType::Date64 => date64_to_datetime(v),
261 DataType::Time32(_) | DataType::Time64(_) => None,
262 DataType::Timestamp(unit, _) => match unit {
263 TimeUnit::Second => timestamp_s_to_datetime(v),
264 TimeUnit::Millisecond => timestamp_ms_to_datetime(v),
265 TimeUnit::Microsecond => timestamp_us_to_datetime(v),
266 TimeUnit::Nanosecond => timestamp_ns_to_datetime(v),
267 },
268 DataType::Interval(_) => None,
270 _ => None,
271 }
272}
273
274pub fn as_datetime_with_timezone<T: ArrowPrimitiveType>(v: i64, tz: Tz) -> Option<DateTime<Tz>> {
276 let naive = as_datetime::<T>(v)?;
277 Some(Utc.from_utc_datetime(&naive).with_timezone(&tz))
278}
279
280pub fn as_date<T: ArrowPrimitiveType>(v: i64) -> Option<NaiveDate> {
282 as_datetime::<T>(v).map(|datetime| datetime.date())
283}
284
285pub fn as_time<T: ArrowPrimitiveType>(v: i64) -> Option<NaiveTime> {
287 match T::DATA_TYPE {
288 DataType::Time32(unit) => {
289 let v = v as u32;
291 match unit {
292 TimeUnit::Second => time32s_to_time(v as i32),
293 TimeUnit::Millisecond => time32ms_to_time(v as i32),
294 _ => None,
295 }
296 }
297 DataType::Time64(unit) => match unit {
298 TimeUnit::Microsecond => time64us_to_time(v),
299 TimeUnit::Nanosecond => time64ns_to_time(v),
300 _ => None,
301 },
302 DataType::Timestamp(_, _) => as_datetime::<T>(v).map(|datetime| datetime.time()),
303 DataType::Date32 | DataType::Date64 => NaiveTime::from_hms_opt(0, 0, 0),
304 DataType::Interval(_) => None,
305 _ => None,
306 }
307}
308
309pub fn as_duration<T: ArrowPrimitiveType>(v: i64) -> Option<Duration> {
311 match T::DATA_TYPE {
312 DataType::Duration(unit) => match unit {
313 TimeUnit::Second => try_duration_s_to_duration(v),
314 TimeUnit::Millisecond => try_duration_ms_to_duration(v),
315 TimeUnit::Microsecond => Some(duration_us_to_duration(v)),
316 TimeUnit::Nanosecond => Some(duration_ns_to_duration(v)),
317 },
318 _ => None,
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use crate::temporal_conversions::{
325 date64_to_datetime, split_second, timestamp_ms_to_datetime, timestamp_ns_to_datetime,
326 timestamp_s_to_date, timestamp_s_to_datetime, timestamp_s_to_time,
327 timestamp_us_to_datetime, NANOSECONDS,
328 };
329 use chrono::DateTime;
330
331 #[test]
332 fn test_timestamp_func() {
333 let timestamp = 1234;
334 let datetime = timestamp_s_to_datetime(timestamp).unwrap();
335 let expected_date = datetime.date();
336 let expected_time = datetime.time();
337
338 assert_eq!(
339 timestamp_s_to_date(timestamp).unwrap().date(),
340 expected_date
341 );
342 assert_eq!(
343 timestamp_s_to_time(timestamp).unwrap().time(),
344 expected_time
345 );
346 }
347
348 #[test]
349 fn negative_input_timestamp_ns_to_datetime() {
350 assert_eq!(
351 timestamp_ns_to_datetime(-1),
352 DateTime::from_timestamp(-1, 999_999_999).map(|x| x.naive_utc())
353 );
354
355 assert_eq!(
356 timestamp_ns_to_datetime(-1_000_000_001),
357 DateTime::from_timestamp(-2, 999_999_999).map(|x| x.naive_utc())
358 );
359 }
360
361 #[test]
362 fn negative_input_timestamp_us_to_datetime() {
363 assert_eq!(
364 timestamp_us_to_datetime(-1),
365 DateTime::from_timestamp(-1, 999_999_000).map(|x| x.naive_utc())
366 );
367
368 assert_eq!(
369 timestamp_us_to_datetime(-1_000_001),
370 DateTime::from_timestamp(-2, 999_999_000).map(|x| x.naive_utc())
371 );
372 }
373
374 #[test]
375 fn negative_input_timestamp_ms_to_datetime() {
376 assert_eq!(
377 timestamp_ms_to_datetime(-1),
378 DateTime::from_timestamp(-1, 999_000_000).map(|x| x.naive_utc())
379 );
380
381 assert_eq!(
382 timestamp_ms_to_datetime(-1_001),
383 DateTime::from_timestamp(-2, 999_000_000).map(|x| x.naive_utc())
384 );
385 }
386
387 #[test]
388 fn negative_input_date64_to_datetime() {
389 assert_eq!(
390 date64_to_datetime(-1),
391 DateTime::from_timestamp(-1, 999_000_000).map(|x| x.naive_utc())
392 );
393
394 assert_eq!(
395 date64_to_datetime(-1_001),
396 DateTime::from_timestamp(-2, 999_000_000).map(|x| x.naive_utc())
397 );
398 }
399
400 #[test]
401 fn test_split_seconds() {
402 let (sec, nano_sec) = split_second(100, NANOSECONDS);
403 assert_eq!(sec, 0);
404 assert_eq!(nano_sec, 100);
405
406 let (sec, nano_sec) = split_second(123_000_000_456, NANOSECONDS);
407 assert_eq!(sec, 123);
408 assert_eq!(nano_sec, 456);
409
410 let (sec, nano_sec) = split_second(-1, NANOSECONDS);
411 assert_eq!(sec, -1);
412 assert_eq!(nano_sec, 999_999_999);
413
414 let (sec, nano_sec) = split_second(-123_000_000_001, NANOSECONDS);
415 assert_eq!(sec, -124);
416 assert_eq!(nano_sec, 999_999_999);
417 }
418}