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