1use std::{
29 fmt::{Display, Formatter},
30 sync::Arc,
31};
32
33use crate::{Bitmask, DatetimeArray, MaskedArray};
34use crate::{
35 enums::{error::MinarrowError, shape_dim::ShapeDim},
36 traits::{concatenate::Concatenate, shape::Shape},
37};
38
39#[repr(C, align(64))]
83#[derive(PartialEq, Clone, Debug, Default)]
84pub enum TemporalArray {
85 Datetime32(Arc<DatetimeArray<i32>>), Datetime64(Arc<DatetimeArray<i64>>),
90 #[default]
91 Null, }
93
94impl TemporalArray {
95 #[inline]
97 pub fn len(&self) -> usize {
98 match self {
99 TemporalArray::Datetime32(arr) => arr.len(),
100 TemporalArray::Datetime64(arr) => arr.len(),
101 TemporalArray::Null => 0,
102 }
103 }
104
105 pub fn delete_range(&mut self, start: usize, end: usize) {
111 match self {
112 TemporalArray::Datetime32(arr) => arr.delete_range(start, end),
113 TemporalArray::Datetime64(arr) => arr.delete_range(start, end),
114 TemporalArray::Null => {
115 assert!(
116 start == 0 && end == 0,
117 "TemporalArray::Null: delete_range out of bounds"
118 );
119 }
120 }
121 }
122
123 #[inline]
125 pub fn null_mask(&self) -> Option<&Bitmask> {
126 match self {
127 TemporalArray::Datetime32(arr) => arr.null_mask.as_ref(),
128 TemporalArray::Datetime64(arr) => arr.null_mask.as_ref(),
129 TemporalArray::Null => None,
130 }
131 }
132
133 #[inline]
138 pub fn has_nulls(&self) -> bool {
139 match self {
140 TemporalArray::Datetime32(arr) => arr.has_nulls(),
141 TemporalArray::Datetime64(arr) => arr.has_nulls(),
142 TemporalArray::Null => false,
143 }
144 }
145
146 pub fn append_array(&mut self, other: &Self) {
158 match (self, other) {
159 (TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => {
160 Arc::make_mut(a).append_array(b)
161 }
162 (TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => {
163 Arc::make_mut(a).append_array(b)
164 }
165 (TemporalArray::Null, TemporalArray::Null) => (),
166 (lhs, rhs) => panic!("Cannot append {:?} into {:?}", rhs, lhs),
167 }
168 }
169
170 pub fn append_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), MinarrowError> {
171 match (self, other) {
172 (TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => Arc::make_mut(a).append_range(b, offset, len),
173 (TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => Arc::make_mut(a).append_range(b, offset, len),
174 (TemporalArray::Null, TemporalArray::Null) => Ok(()),
175 (lhs, rhs) => Err(MinarrowError::TypeError {
176 from: "TemporalArray",
177 to: "TemporalArray",
178 message: Some(format!("Cannot append_range {:?} into {:?}", rhs, lhs)),
179 }),
180 }
181 }
182
183 pub fn insert_rows(&mut self, index: usize, other: &Self) -> Result<(), MinarrowError> {
192 match (self, other) {
193 (TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => {
194 Arc::make_mut(a).insert_rows(index, b)
195 }
196 (TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => {
197 Arc::make_mut(a).insert_rows(index, b)
198 }
199 (TemporalArray::Null, TemporalArray::Null) => Ok(()),
200 (lhs, rhs) => Err(MinarrowError::TypeError {
201 from: "TemporalArray",
202 to: "TemporalArray",
203 message: Some(format!(
204 "Cannot insert {} into {}: incompatible types",
205 temporal_variant_name(rhs),
206 temporal_variant_name(lhs)
207 )),
208 }),
209 }
210 }
211
212 pub fn split(self, index: usize) -> Result<(Self, Self), MinarrowError> {
214 use std::sync::Arc;
215
216 match self {
217 TemporalArray::Datetime32(a) => {
218 let (left, right) = Arc::try_unwrap(a)
219 .unwrap_or_else(|arc| (*arc).clone())
220 .split(index)?;
221 Ok((
222 TemporalArray::Datetime32(Arc::new(left)),
223 TemporalArray::Datetime32(Arc::new(right)),
224 ))
225 }
226 TemporalArray::Datetime64(a) => {
227 let (left, right) = Arc::try_unwrap(a)
228 .unwrap_or_else(|arc| (*arc).clone())
229 .split(index)?;
230 Ok((
231 TemporalArray::Datetime64(Arc::new(left)),
232 TemporalArray::Datetime64(Arc::new(right)),
233 ))
234 }
235 TemporalArray::Null => Err(MinarrowError::IndexError(
236 "Cannot split Null array".to_string(),
237 )),
238 }
239 }
240
241 #[inline]
246 pub fn dt32(&self) -> Arc<DatetimeArray<i32>> {
247 self.try_dt32().unwrap()
248 }
249
250 pub fn try_dt32(&self) -> Result<Arc<DatetimeArray<i32>>, MinarrowError> {
254 match self {
255 TemporalArray::Datetime32(arr) => Ok(arr.clone()),
256 TemporalArray::Datetime64(arr) => Ok(Arc::new(DatetimeArray::<i32>::try_from(&**arr)?)),
257 TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
258 }
259 }
260
261 #[inline]
266 pub fn dt64(&self) -> Arc<DatetimeArray<i64>> {
267 self.try_dt64().unwrap()
268 }
269
270 pub fn try_dt64(&self) -> Result<Arc<DatetimeArray<i64>>, MinarrowError> {
274 match self {
275 TemporalArray::Datetime64(arr) => Ok(arr.clone()),
276 TemporalArray::Datetime32(arr) => Ok(Arc::new(DatetimeArray::<i64>::from(&**arr))),
277 TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
278 }
279 }
280}
281
282impl Shape for TemporalArray {
283 fn shape(&self) -> ShapeDim {
284 ShapeDim::Rank1(self.len())
285 }
286}
287
288impl Concatenate for TemporalArray {
289 fn concat(self, other: Self) -> Result<Self, MinarrowError> {
290 match (self, other) {
291 (TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => {
292 let a = Arc::try_unwrap(a).unwrap_or_else(|arc| (*arc).clone());
293 let b = Arc::try_unwrap(b).unwrap_or_else(|arc| (*arc).clone());
294 Ok(TemporalArray::Datetime32(Arc::new(a.concat(b)?)))
295 }
296 (TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => {
297 let a = Arc::try_unwrap(a).unwrap_or_else(|arc| (*arc).clone());
298 let b = Arc::try_unwrap(b).unwrap_or_else(|arc| (*arc).clone());
299 Ok(TemporalArray::Datetime64(Arc::new(a.concat(b)?)))
300 }
301 (TemporalArray::Null, TemporalArray::Null) => Ok(TemporalArray::Null),
302 (lhs, rhs) => Err(MinarrowError::IncompatibleTypeError {
303 from: "TemporalArray",
304 to: "TemporalArray",
305 message: Some(format!(
306 "Cannot concatenate mismatched TemporalArray variants: {:?} and {:?}",
307 temporal_variant_name(&lhs),
308 temporal_variant_name(&rhs)
309 )),
310 }),
311 }
312 }
313}
314
315#[cfg(feature = "datetime_ops")]
316use crate::DatetimeOps;
317
318#[cfg(feature = "datetime_ops")]
319use crate::enums::time_units::TimeUnit;
320
321#[cfg(feature = "datetime_ops")]
322use time::Duration;
323
324#[cfg(feature = "datetime_ops")]
325use crate::structs::variants::{boolean::BooleanArray, integer::IntegerArray};
326
327#[cfg(feature = "datetime_ops")]
328impl DatetimeOps for TemporalArray {
329 fn year(&self) -> IntegerArray<i32> {
332 match self {
333 TemporalArray::Datetime32(arr) => arr.year(),
334 TemporalArray::Datetime64(arr) => arr.year(),
335 TemporalArray::Null => IntegerArray::default(),
336 }
337 }
338
339 fn month(&self) -> IntegerArray<i32> {
340 match self {
341 TemporalArray::Datetime32(arr) => arr.month(),
342 TemporalArray::Datetime64(arr) => arr.month(),
343 TemporalArray::Null => IntegerArray::default(),
344 }
345 }
346
347 fn day(&self) -> IntegerArray<i32> {
348 match self {
349 TemporalArray::Datetime32(arr) => arr.day(),
350 TemporalArray::Datetime64(arr) => arr.day(),
351 TemporalArray::Null => IntegerArray::default(),
352 }
353 }
354
355 fn hour(&self) -> IntegerArray<i32> {
356 match self {
357 TemporalArray::Datetime32(arr) => arr.hour(),
358 TemporalArray::Datetime64(arr) => arr.hour(),
359 TemporalArray::Null => IntegerArray::default(),
360 }
361 }
362
363 fn minute(&self) -> IntegerArray<i32> {
364 match self {
365 TemporalArray::Datetime32(arr) => arr.minute(),
366 TemporalArray::Datetime64(arr) => arr.minute(),
367 TemporalArray::Null => IntegerArray::default(),
368 }
369 }
370
371 fn second(&self) -> IntegerArray<i32> {
372 match self {
373 TemporalArray::Datetime32(arr) => arr.second(),
374 TemporalArray::Datetime64(arr) => arr.second(),
375 TemporalArray::Null => IntegerArray::default(),
376 }
377 }
378
379 fn weekday(&self) -> IntegerArray<i32> {
380 match self {
381 TemporalArray::Datetime32(arr) => arr.weekday(),
382 TemporalArray::Datetime64(arr) => arr.weekday(),
383 TemporalArray::Null => IntegerArray::default(),
384 }
385 }
386
387 fn day_of_year(&self) -> IntegerArray<i32> {
388 match self {
389 TemporalArray::Datetime32(arr) => arr.day_of_year(),
390 TemporalArray::Datetime64(arr) => arr.day_of_year(),
391 TemporalArray::Null => IntegerArray::default(),
392 }
393 }
394
395 fn iso_week(&self) -> IntegerArray<i32> {
396 match self {
397 TemporalArray::Datetime32(arr) => arr.iso_week(),
398 TemporalArray::Datetime64(arr) => arr.iso_week(),
399 TemporalArray::Null => IntegerArray::default(),
400 }
401 }
402
403 fn quarter(&self) -> IntegerArray<i32> {
404 match self {
405 TemporalArray::Datetime32(arr) => arr.quarter(),
406 TemporalArray::Datetime64(arr) => arr.quarter(),
407 TemporalArray::Null => IntegerArray::default(),
408 }
409 }
410
411 fn week_of_year(&self) -> IntegerArray<i32> {
412 match self {
413 TemporalArray::Datetime32(arr) => arr.week_of_year(),
414 TemporalArray::Datetime64(arr) => arr.week_of_year(),
415 TemporalArray::Null => IntegerArray::default(),
416 }
417 }
418
419 fn is_leap_year(&self) -> BooleanArray<()> {
420 match self {
421 TemporalArray::Datetime32(arr) => arr.is_leap_year(),
422 TemporalArray::Datetime64(arr) => arr.is_leap_year(),
423 TemporalArray::Null => BooleanArray::default(),
424 }
425 }
426
427 fn add_duration(&self, duration: Duration) -> Result<Self, MinarrowError> {
430 match self {
431 TemporalArray::Datetime32(arr) => Ok(TemporalArray::Datetime32(Arc::new(
432 arr.add_duration(duration)?,
433 ))),
434 TemporalArray::Datetime64(arr) => Ok(TemporalArray::Datetime64(Arc::new(
435 arr.add_duration(duration)?,
436 ))),
437 TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
438 }
439 }
440
441 fn sub_duration(&self, duration: Duration) -> Result<Self, MinarrowError> {
442 match self {
443 TemporalArray::Datetime32(arr) => Ok(TemporalArray::Datetime32(Arc::new(
444 arr.sub_duration(duration)?,
445 ))),
446 TemporalArray::Datetime64(arr) => Ok(TemporalArray::Datetime64(Arc::new(
447 arr.sub_duration(duration)?,
448 ))),
449 TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
450 }
451 }
452
453 fn add_days(&self, days: i64) -> Result<Self, MinarrowError> {
454 match self {
455 TemporalArray::Datetime32(arr) => {
456 Ok(TemporalArray::Datetime32(Arc::new(arr.add_days(days)?)))
457 }
458 TemporalArray::Datetime64(arr) => {
459 Ok(TemporalArray::Datetime64(Arc::new(arr.add_days(days)?)))
460 }
461 TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
462 }
463 }
464
465 fn add_months(&self, months: i32) -> Result<Self, MinarrowError> {
466 match self {
467 TemporalArray::Datetime32(arr) => {
468 Ok(TemporalArray::Datetime32(Arc::new(arr.add_months(months)?)))
469 }
470 TemporalArray::Datetime64(arr) => {
471 Ok(TemporalArray::Datetime64(Arc::new(arr.add_months(months)?)))
472 }
473 TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
474 }
475 }
476
477 fn add_years(&self, years: i32) -> Result<Self, MinarrowError> {
478 match self {
479 TemporalArray::Datetime32(arr) => {
480 Ok(TemporalArray::Datetime32(Arc::new(arr.add_years(years)?)))
481 }
482 TemporalArray::Datetime64(arr) => {
483 Ok(TemporalArray::Datetime64(Arc::new(arr.add_years(years)?)))
484 }
485 TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
486 }
487 }
488
489 fn diff(&self, other: &Self, unit: TimeUnit) -> Result<IntegerArray<i64>, MinarrowError> {
492 match (self, other) {
493 (TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => a.diff(b, unit),
494 (TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => a.diff(b, unit),
495 (TemporalArray::Null, _) | (_, TemporalArray::Null) => {
496 Err(MinarrowError::NullError { message: None })
497 }
498 _ => Err(MinarrowError::TypeError {
499 from: "TemporalArray",
500 to: "TemporalArray",
501 message: Some("Mismatched temporal variants".to_string()),
502 }),
503 }
504 }
505
506 fn abs_diff(&self, other: &Self, unit: TimeUnit) -> Result<IntegerArray<i64>, MinarrowError> {
507 match (self, other) {
508 (TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => a.abs_diff(b, unit),
509 (TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => a.abs_diff(b, unit),
510 (TemporalArray::Null, _) | (_, TemporalArray::Null) => {
511 Err(MinarrowError::NullError { message: None })
512 }
513 _ => Err(MinarrowError::TypeError {
514 from: "TemporalArray",
515 to: "TemporalArray",
516 message: Some("Mismatched temporal variants".to_string()),
517 }),
518 }
519 }
520
521 fn is_before(&self, other: &Self) -> Result<BooleanArray<()>, MinarrowError> {
522 match (self, other) {
523 (TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => a.is_before(b),
524 (TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => a.is_before(b),
525 (TemporalArray::Null, _) | (_, TemporalArray::Null) => {
526 Err(MinarrowError::NullError { message: None })
527 }
528 _ => Err(MinarrowError::TypeError {
529 from: "TemporalArray",
530 to: "TemporalArray",
531 message: Some("Mismatched temporal variants".to_string()),
532 }),
533 }
534 }
535
536 fn is_after(&self, other: &Self) -> Result<BooleanArray<()>, MinarrowError> {
537 match (self, other) {
538 (TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => a.is_after(b),
539 (TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => a.is_after(b),
540 (TemporalArray::Null, _) | (_, TemporalArray::Null) => {
541 Err(MinarrowError::NullError { message: None })
542 }
543 _ => Err(MinarrowError::TypeError {
544 from: "TemporalArray",
545 to: "TemporalArray",
546 message: Some("Mismatched temporal variants".to_string()),
547 }),
548 }
549 }
550
551 fn between(&self, start: &Self, end: &Self) -> Result<BooleanArray<()>, MinarrowError> {
552 match (self, start, end) {
553 (
554 TemporalArray::Datetime32(a),
555 TemporalArray::Datetime32(s),
556 TemporalArray::Datetime32(e),
557 ) => a.between(s, e),
558 (
559 TemporalArray::Datetime64(a),
560 TemporalArray::Datetime64(s),
561 TemporalArray::Datetime64(e),
562 ) => a.between(s, e),
563 (TemporalArray::Null, _, _)
564 | (_, TemporalArray::Null, _)
565 | (_, _, TemporalArray::Null) => Err(MinarrowError::NullError { message: None }),
566 _ => Err(MinarrowError::TypeError {
567 from: "TemporalArray",
568 to: "TemporalArray",
569 message: Some("Mismatched temporal variants".to_string()),
570 }),
571 }
572 }
573
574 fn truncate(&self, unit: &str) -> Result<Self, MinarrowError> {
577 match self {
578 TemporalArray::Datetime32(arr) => {
579 Ok(TemporalArray::Datetime32(Arc::new(arr.truncate(unit)?)))
580 }
581 TemporalArray::Datetime64(arr) => {
582 Ok(TemporalArray::Datetime64(Arc::new(arr.truncate(unit)?)))
583 }
584 TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
585 }
586 }
587
588 fn us(&self) -> Self {
589 match self {
590 TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.us())),
591 TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.us())),
592 TemporalArray::Null => TemporalArray::Null,
593 }
594 }
595
596 fn ms(&self) -> Self {
597 match self {
598 TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.ms())),
599 TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.ms())),
600 TemporalArray::Null => TemporalArray::Null,
601 }
602 }
603
604 fn sec(&self) -> Self {
605 match self {
606 TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.sec())),
607 TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.sec())),
608 TemporalArray::Null => TemporalArray::Null,
609 }
610 }
611
612 fn min(&self) -> Self {
613 match self {
614 TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.min())),
615 TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.min())),
616 TemporalArray::Null => TemporalArray::Null,
617 }
618 }
619
620 fn hr(&self) -> Self {
621 match self {
622 TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.hr())),
623 TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.hr())),
624 TemporalArray::Null => TemporalArray::Null,
625 }
626 }
627
628 fn week(&self) -> Self {
629 match self {
630 TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.week())),
631 TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.week())),
632 TemporalArray::Null => TemporalArray::Null,
633 }
634 }
635
636 fn cast_time_unit(&self, new_unit: TimeUnit) -> Result<Self, MinarrowError> {
639 match self {
640 TemporalArray::Datetime32(arr) => Ok(TemporalArray::Datetime32(Arc::new(
641 arr.cast_time_unit(new_unit)?,
642 ))),
643 TemporalArray::Datetime64(arr) => Ok(TemporalArray::Datetime64(Arc::new(
644 arr.cast_time_unit(new_unit)?,
645 ))),
646 TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
647 }
648 }
649}
650
651fn temporal_variant_name(arr: &TemporalArray) -> &'static str {
653 match arr {
654 TemporalArray::Datetime32(_) => "Datetime32",
655 TemporalArray::Datetime64(_) => "Datetime64",
656 TemporalArray::Null => "Null",
657 }
658}
659
660impl Display for TemporalArray {
661 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
662 match self {
663 TemporalArray::Datetime32(arr) => {
664 write_temporal_array_with_header(f, "Datetime32", arr.as_ref())
665 }
666 TemporalArray::Datetime64(arr) => {
667 write_temporal_array_with_header(f, "Datetime64", arr.as_ref())
668 }
669 TemporalArray::Null => writeln!(f, "TemporalArray::Null [0 values]"),
670 }
671 }
672}
673
674fn write_temporal_array_with_header(
676 f: &mut Formatter<'_>,
677 dtype: &str,
678 arr: &(impl MaskedArray + Display + ?Sized),
679) -> std::fmt::Result {
680 writeln!(
681 f,
682 "TemporalArray [{dtype}] [{} values] (null count: {})",
683 arr.len(),
684 arr.null_count()
685 )?;
686 Display::fmt(arr, f)
687}