Skip to main content

arrow_array/
types.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Zero-sized types used to parameterize generic array implementations
19
20use crate::delta::{
21    add_days_datetime, add_months_date, add_months_datetime, sub_days_datetime, sub_months_datetime,
22};
23use crate::temporal_conversions::as_datetime_with_timezone;
24use crate::timezone::Tz;
25use crate::{ArrowNativeTypeOp, OffsetSizeTrait};
26use arrow_buffer::{Buffer, OffsetBuffer, i256};
27use arrow_data::decimal::{
28    format_decimal_str, is_validate_decimal_precision, is_validate_decimal32_precision,
29    is_validate_decimal64_precision, is_validate_decimal256_precision, validate_decimal_precision,
30    validate_decimal32_precision, validate_decimal64_precision, validate_decimal256_precision,
31};
32use arrow_data::{validate_binary_view, validate_string_view};
33use arrow_schema::{
34    ArrowError, DECIMAL_DEFAULT_SCALE, DECIMAL32_DEFAULT_SCALE, DECIMAL32_MAX_PRECISION,
35    DECIMAL32_MAX_SCALE, DECIMAL64_DEFAULT_SCALE, DECIMAL64_MAX_PRECISION, DECIMAL64_MAX_SCALE,
36    DECIMAL128_MAX_PRECISION, DECIMAL128_MAX_SCALE, DECIMAL256_MAX_PRECISION, DECIMAL256_MAX_SCALE,
37    DataType, IntervalUnit, TimeUnit,
38};
39use chrono::{DateTime, Duration, NaiveDate, NaiveDateTime, TimeZone};
40use half::f16;
41use std::fmt::Debug;
42use std::marker::PhantomData;
43use std::ops::Sub;
44
45// re-export types so that they can be used without importing arrow_buffer explicitly
46pub use arrow_buffer::{IntervalDayTime, IntervalMonthDayNano};
47
48// BooleanType is special: its bit-width is not the size of the primitive type, and its `index`
49// operation assumes bit-packing.
50/// A boolean datatype
51#[derive(Debug)]
52pub struct BooleanType {}
53
54impl BooleanType {
55    /// The corresponding Arrow data type
56    pub const DATA_TYPE: DataType = DataType::Boolean;
57}
58
59/// Trait for [primitive values].
60///
61/// This trait bridges the dynamic-typed nature of Arrow
62/// (via [`DataType`]) with the static-typed nature of rust types
63/// ([`ArrowNativeType`]) for all types that implement [`ArrowNativeType`].
64///
65/// [primitive values]: https://arrow.apache.org/docs/format/Columnar.html#fixed-size-primitive-layout
66/// [`ArrowNativeType`]: arrow_buffer::ArrowNativeType
67pub trait ArrowPrimitiveType: primitive::PrimitiveTypeSealed + 'static {
68    /// Corresponding Rust native type for the primitive type.
69    type Native: ArrowNativeTypeOp;
70
71    /// the corresponding Arrow data type of this primitive type.
72    const DATA_TYPE: DataType;
73
74    /// Returns a default value of this primitive type.
75    ///
76    /// This is useful for aggregate array ops like `sum()`, `mean()`.
77    fn default_value() -> Self::Native {
78        Default::default()
79    }
80}
81
82mod primitive {
83    pub trait PrimitiveTypeSealed {}
84}
85
86macro_rules! make_type {
87    ($name:ident, $native_ty:ty, $data_ty:expr, $doc_string: literal) => {
88        #[derive(Debug)]
89        #[doc = $doc_string]
90        pub struct $name {}
91
92        impl ArrowPrimitiveType for $name {
93            type Native = $native_ty;
94            const DATA_TYPE: DataType = $data_ty;
95        }
96
97        impl primitive::PrimitiveTypeSealed for $name {}
98    };
99}
100
101make_type!(Int8Type, i8, DataType::Int8, "A signed 8-bit integer type.");
102make_type!(
103    Int16Type,
104    i16,
105    DataType::Int16,
106    "Signed 16-bit integer type."
107);
108make_type!(
109    Int32Type,
110    i32,
111    DataType::Int32,
112    "Signed 32-bit integer type."
113);
114make_type!(
115    Int64Type,
116    i64,
117    DataType::Int64,
118    "Signed 64-bit integer type."
119);
120make_type!(
121    UInt8Type,
122    u8,
123    DataType::UInt8,
124    "Unsigned 8-bit integer type."
125);
126make_type!(
127    UInt16Type,
128    u16,
129    DataType::UInt16,
130    "Unsigned 16-bit integer type."
131);
132make_type!(
133    UInt32Type,
134    u32,
135    DataType::UInt32,
136    "Unsigned 32-bit integer type."
137);
138make_type!(
139    UInt64Type,
140    u64,
141    DataType::UInt64,
142    "Unsigned 64-bit integer type."
143);
144make_type!(
145    Float16Type,
146    f16,
147    DataType::Float16,
148    "16-bit floating point number type."
149);
150make_type!(
151    Float32Type,
152    f32,
153    DataType::Float32,
154    "32-bit floating point number type."
155);
156make_type!(
157    Float64Type,
158    f64,
159    DataType::Float64,
160    "64-bit floating point number type."
161);
162make_type!(
163    TimestampSecondType,
164    i64,
165    DataType::Timestamp(TimeUnit::Second, None),
166    "Timestamp second type with an optional timezone."
167);
168make_type!(
169    TimestampMillisecondType,
170    i64,
171    DataType::Timestamp(TimeUnit::Millisecond, None),
172    "Timestamp millisecond type with an optional timezone."
173);
174make_type!(
175    TimestampMicrosecondType,
176    i64,
177    DataType::Timestamp(TimeUnit::Microsecond, None),
178    "Timestamp microsecond type with an optional timezone."
179);
180make_type!(
181    TimestampNanosecondType,
182    i64,
183    DataType::Timestamp(TimeUnit::Nanosecond, None),
184    "Timestamp nanosecond type with an optional timezone."
185);
186make_type!(
187    Date32Type,
188    i32,
189    DataType::Date32,
190    "32-bit date type: the elapsed time since UNIX epoch in days (32 bits)."
191);
192make_type!(
193    Date64Type,
194    i64,
195    DataType::Date64,
196    "64-bit date type: the elapsed time since UNIX epoch in milliseconds (64 bits). \
197    Values must be divisible by `86_400_000`. \
198    See [`DataType::Date64`] for more details."
199);
200make_type!(
201    Time32SecondType,
202    i32,
203    DataType::Time32(TimeUnit::Second),
204    "32-bit time type: the elapsed time since midnight in seconds."
205);
206make_type!(
207    Time32MillisecondType,
208    i32,
209    DataType::Time32(TimeUnit::Millisecond),
210    "32-bit time type: the elapsed time since midnight in milliseconds."
211);
212make_type!(
213    Time64MicrosecondType,
214    i64,
215    DataType::Time64(TimeUnit::Microsecond),
216    "64-bit time type: the elapsed time since midnight in microseconds."
217);
218make_type!(
219    Time64NanosecondType,
220    i64,
221    DataType::Time64(TimeUnit::Nanosecond),
222    "64-bit time type: the elapsed time since midnight in nanoseconds."
223);
224make_type!(
225    IntervalYearMonthType,
226    i32,
227    DataType::Interval(IntervalUnit::YearMonth),
228    "32-bit “calendar” interval type: the number of whole months."
229);
230make_type!(
231    IntervalDayTimeType,
232    IntervalDayTime,
233    DataType::Interval(IntervalUnit::DayTime),
234    "“Calendar” interval type: days and milliseconds. See [`IntervalDayTime`] for more details."
235);
236make_type!(
237    IntervalMonthDayNanoType,
238    IntervalMonthDayNano,
239    DataType::Interval(IntervalUnit::MonthDayNano),
240    r"“Calendar” interval type: months, days, and nanoseconds. See [`IntervalMonthDayNano`] for more details."
241);
242make_type!(
243    DurationSecondType,
244    i64,
245    DataType::Duration(TimeUnit::Second),
246    "Elapsed time type: seconds."
247);
248make_type!(
249    DurationMillisecondType,
250    i64,
251    DataType::Duration(TimeUnit::Millisecond),
252    "Elapsed time type: milliseconds."
253);
254make_type!(
255    DurationMicrosecondType,
256    i64,
257    DataType::Duration(TimeUnit::Microsecond),
258    "Elapsed time type: microseconds."
259);
260make_type!(
261    DurationNanosecondType,
262    i64,
263    DataType::Duration(TimeUnit::Nanosecond),
264    "Elapsed time type: nanoseconds."
265);
266
267/// A subtype of primitive type that represents legal dictionary keys.
268/// See <https://arrow.apache.org/docs/format/Columnar.html>
269pub trait ArrowDictionaryKeyType: ArrowPrimitiveType {}
270
271impl ArrowDictionaryKeyType for Int8Type {}
272
273impl ArrowDictionaryKeyType for Int16Type {}
274
275impl ArrowDictionaryKeyType for Int32Type {}
276
277impl ArrowDictionaryKeyType for Int64Type {}
278
279impl ArrowDictionaryKeyType for UInt8Type {}
280
281impl ArrowDictionaryKeyType for UInt16Type {}
282
283impl ArrowDictionaryKeyType for UInt32Type {}
284
285impl ArrowDictionaryKeyType for UInt64Type {}
286
287/// A subtype of primitive type that is used as run-ends index
288/// in `RunArray`.
289/// See <https://arrow.apache.org/docs/format/Columnar.html>
290pub trait RunEndIndexType: ArrowPrimitiveType {}
291
292impl RunEndIndexType for Int16Type {}
293
294impl RunEndIndexType for Int32Type {}
295
296impl RunEndIndexType for Int64Type {}
297
298/// A subtype of primitive type that represents temporal values.
299pub trait ArrowTemporalType: ArrowPrimitiveType {}
300
301impl ArrowTemporalType for TimestampSecondType {}
302impl ArrowTemporalType for TimestampMillisecondType {}
303impl ArrowTemporalType for TimestampMicrosecondType {}
304impl ArrowTemporalType for TimestampNanosecondType {}
305impl ArrowTemporalType for Date32Type {}
306impl ArrowTemporalType for Date64Type {}
307impl ArrowTemporalType for Time32SecondType {}
308impl ArrowTemporalType for Time32MillisecondType {}
309impl ArrowTemporalType for Time64MicrosecondType {}
310impl ArrowTemporalType for Time64NanosecondType {}
311// impl ArrowTemporalType for IntervalYearMonthType {}
312// impl ArrowTemporalType for IntervalDayTimeType {}
313// impl ArrowTemporalType for IntervalMonthDayNanoType {}
314impl ArrowTemporalType for DurationSecondType {}
315impl ArrowTemporalType for DurationMillisecondType {}
316impl ArrowTemporalType for DurationMicrosecondType {}
317impl ArrowTemporalType for DurationNanosecondType {}
318
319/// A timestamp type allows us to create array builders that take a timestamp.
320pub trait ArrowTimestampType: ArrowTemporalType<Native = i64> {
321    /// The [`TimeUnit`] of this timestamp.
322    const UNIT: TimeUnit;
323
324    /// Creates a ArrowTimestampType::Native from the provided [`NaiveDateTime`]
325    ///
326    /// See [`DataType::Timestamp`] for more information on timezone handling
327    fn make_value(naive: NaiveDateTime) -> Option<i64>;
328
329    /// Creates a timestamp value from a [`DateTime`] in any timezone.
330    ///
331    /// Returns `None` if the timestamp value would overflow the i64 range
332    /// (e.g., for nanosecond precision with extreme datetime values).
333    ///
334    /// # Arguments
335    ///
336    /// * `datetime` - The datetime to convert
337    fn from_datetime<Tz: TimeZone>(datetime: DateTime<Tz>) -> Option<i64>;
338
339    /// Creates a timestamp value from a [`NaiveDateTime`] interpreted in the given timezone.
340    ///
341    /// # Arguments
342    ///
343    /// * `naive` - The local datetime to convert
344    /// * `tz` - Optional timezone. If `None`, interprets as UTC
345    ///   (equivalent to calling [`Self::make_value`]).
346    fn from_naive_datetime(naive: NaiveDateTime, tz: Option<&Tz>) -> Option<i64> {
347        match tz {
348            Some(tz) => match tz.from_local_datetime(&naive) {
349                chrono::offset::LocalResult::Single(dt) => Self::from_datetime(dt),
350                chrono::offset::LocalResult::Ambiguous(dt1, _) => Self::from_datetime(dt1),
351                chrono::offset::LocalResult::None => None,
352            },
353            None => Self::make_value(naive),
354        }
355    }
356}
357
358impl ArrowTimestampType for TimestampSecondType {
359    const UNIT: TimeUnit = TimeUnit::Second;
360
361    fn make_value(naive: NaiveDateTime) -> Option<i64> {
362        Some(naive.and_utc().timestamp())
363    }
364
365    fn from_datetime<Tz: TimeZone>(datetime: DateTime<Tz>) -> Option<i64> {
366        Some(datetime.timestamp())
367    }
368}
369impl ArrowTimestampType for TimestampMillisecondType {
370    const UNIT: TimeUnit = TimeUnit::Millisecond;
371
372    fn make_value(naive: NaiveDateTime) -> Option<i64> {
373        let utc = naive.and_utc();
374        let millis = utc.timestamp().checked_mul(1_000)?;
375        millis.checked_add(utc.timestamp_subsec_millis() as i64)
376    }
377
378    fn from_datetime<Tz: TimeZone>(datetime: DateTime<Tz>) -> Option<i64> {
379        let millis = datetime.timestamp().checked_mul(1_000)?;
380        millis.checked_add(datetime.timestamp_subsec_millis() as i64)
381    }
382}
383impl ArrowTimestampType for TimestampMicrosecondType {
384    const UNIT: TimeUnit = TimeUnit::Microsecond;
385
386    fn make_value(naive: NaiveDateTime) -> Option<i64> {
387        let utc = naive.and_utc();
388        let micros = utc.timestamp().checked_mul(1_000_000)?;
389        micros.checked_add(utc.timestamp_subsec_micros() as i64)
390    }
391
392    fn from_datetime<Tz: TimeZone>(datetime: DateTime<Tz>) -> Option<i64> {
393        let micros = datetime.timestamp().checked_mul(1_000_000)?;
394        micros.checked_add(datetime.timestamp_subsec_micros() as i64)
395    }
396}
397impl ArrowTimestampType for TimestampNanosecondType {
398    const UNIT: TimeUnit = TimeUnit::Nanosecond;
399
400    fn make_value(naive: NaiveDateTime) -> Option<i64> {
401        let utc = naive.and_utc();
402        let nanos = utc.timestamp().checked_mul(1_000_000_000)?;
403        nanos.checked_add(utc.timestamp_subsec_nanos() as i64)
404    }
405
406    fn from_datetime<Tz: TimeZone>(datetime: DateTime<Tz>) -> Option<i64> {
407        datetime.timestamp_nanos_opt()
408    }
409}
410
411fn add_year_months<T: ArrowTimestampType>(
412    timestamp: <T as ArrowPrimitiveType>::Native,
413    delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
414    tz: Tz,
415) -> Option<<T as ArrowPrimitiveType>::Native> {
416    let months = IntervalYearMonthType::to_months(delta);
417    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
418    let res = add_months_datetime(res, months)?;
419    let res = res.naive_utc();
420    T::make_value(res)
421}
422
423fn add_day_time<T: ArrowTimestampType>(
424    timestamp: <T as ArrowPrimitiveType>::Native,
425    delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
426    tz: Tz,
427) -> Option<<T as ArrowPrimitiveType>::Native> {
428    let (days, ms) = IntervalDayTimeType::to_parts(delta);
429    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
430    let res = add_days_datetime(res, days)?;
431    let res = res.checked_add_signed(Duration::try_milliseconds(ms as i64)?)?;
432    let res = res.naive_utc();
433    T::make_value(res)
434}
435
436fn add_month_day_nano<T: ArrowTimestampType>(
437    timestamp: <T as ArrowPrimitiveType>::Native,
438    delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
439    tz: Tz,
440) -> Option<<T as ArrowPrimitiveType>::Native> {
441    let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
442    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
443    let res = add_months_datetime(res, months)?;
444    let res = add_days_datetime(res, days)?;
445    let res = res.checked_add_signed(Duration::nanoseconds(nanos))?;
446    let res = res.naive_utc();
447    T::make_value(res)
448}
449
450fn subtract_year_months<T: ArrowTimestampType>(
451    timestamp: <T as ArrowPrimitiveType>::Native,
452    delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
453    tz: Tz,
454) -> Option<<T as ArrowPrimitiveType>::Native> {
455    let months = IntervalYearMonthType::to_months(delta);
456    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
457    let res = sub_months_datetime(res, months)?;
458    let res = res.naive_utc();
459    T::make_value(res)
460}
461
462fn subtract_day_time<T: ArrowTimestampType>(
463    timestamp: <T as ArrowPrimitiveType>::Native,
464    delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
465    tz: Tz,
466) -> Option<<T as ArrowPrimitiveType>::Native> {
467    let (days, ms) = IntervalDayTimeType::to_parts(delta);
468    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
469    let res = sub_days_datetime(res, days)?;
470    let res = res.checked_sub_signed(Duration::try_milliseconds(ms as i64)?)?;
471    let res = res.naive_utc();
472    T::make_value(res)
473}
474
475fn subtract_month_day_nano<T: ArrowTimestampType>(
476    timestamp: <T as ArrowPrimitiveType>::Native,
477    delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
478    tz: Tz,
479) -> Option<<T as ArrowPrimitiveType>::Native> {
480    let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
481    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
482    let res = sub_months_datetime(res, months)?;
483    let res = sub_days_datetime(res, days)?;
484    let res = res.checked_sub_signed(Duration::nanoseconds(nanos))?;
485    let res = res.naive_utc();
486    T::make_value(res)
487}
488
489impl TimestampSecondType {
490    /// Adds the given IntervalYearMonthType to an arrow TimestampSecondType.
491    ///
492    /// Returns `None` when it will result in overflow.
493    ///
494    /// # Arguments
495    ///
496    /// * `timestamp` - The date on which to perform the operation
497    /// * `delta` - The interval to add
498    /// * `tz` - The timezone in which to interpret `timestamp`
499    pub fn add_year_months(
500        timestamp: <Self as ArrowPrimitiveType>::Native,
501        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
502        tz: Tz,
503    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
504        add_year_months::<Self>(timestamp, delta, tz)
505    }
506
507    /// Adds the given IntervalDayTimeType to an arrow TimestampSecondType.
508    ///
509    /// Returns `None` when it will result in overflow.
510    ///
511    /// # Arguments
512    ///
513    /// * `timestamp` - The date on which to perform the operation
514    /// * `delta` - The interval to add
515    /// * `tz` - The timezone in which to interpret `timestamp`
516    pub fn add_day_time(
517        timestamp: <Self as ArrowPrimitiveType>::Native,
518        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
519        tz: Tz,
520    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
521        add_day_time::<Self>(timestamp, delta, tz)
522    }
523
524    /// Adds the given IntervalMonthDayNanoType to an arrow TimestampSecondType
525    ///
526    /// Returns `None` when it will result in overflow.
527    /// # Arguments
528    ///
529    /// * `timestamp` - The date on which to perform the operation
530    /// * `delta` - The interval to add
531    /// * `tz` - The timezone in which to interpret `timestamp`
532    pub fn add_month_day_nano(
533        timestamp: <Self as ArrowPrimitiveType>::Native,
534        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
535        tz: Tz,
536    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
537        add_month_day_nano::<Self>(timestamp, delta, tz)
538    }
539
540    /// Subtracts the given IntervalYearMonthType to an arrow TimestampSecondType
541    ///
542    /// Returns `None` when it will result in overflow.
543    ///
544    /// # Arguments
545    ///
546    /// * `timestamp` - The date on which to perform the operation
547    /// * `delta` - The interval to add
548    /// * `tz` - The timezone in which to interpret `timestamp`
549    pub fn subtract_year_months(
550        timestamp: <Self as ArrowPrimitiveType>::Native,
551        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
552        tz: Tz,
553    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
554        subtract_year_months::<Self>(timestamp, delta, tz)
555    }
556
557    /// Subtracts the given IntervalDayTimeType to an arrow TimestampSecondType
558    ///
559    /// Returns `None` when it will result in overflow.
560    ///
561    /// # Arguments
562    ///
563    /// * `timestamp` - The date on which to perform the operation
564    /// * `delta` - The interval to add
565    /// * `tz` - The timezone in which to interpret `timestamp`
566    pub fn subtract_day_time(
567        timestamp: <Self as ArrowPrimitiveType>::Native,
568        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
569        tz: Tz,
570    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
571        subtract_day_time::<Self>(timestamp, delta, tz)
572    }
573
574    /// Subtracts the given IntervalMonthDayNanoType to an arrow TimestampSecondType
575    ///
576    /// Returns `None` when it will result in overflow.
577    ///
578    /// # Arguments
579    ///
580    /// * `timestamp` - The date on which to perform the operation
581    /// * `delta` - The interval to add
582    /// * `tz` - The timezone in which to interpret `timestamp`
583    pub fn subtract_month_day_nano(
584        timestamp: <Self as ArrowPrimitiveType>::Native,
585        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
586        tz: Tz,
587    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
588        subtract_month_day_nano::<Self>(timestamp, delta, tz)
589    }
590}
591
592impl TimestampMicrosecondType {
593    /// Adds the given IntervalYearMonthType to an arrow TimestampMicrosecondType
594    ///
595    /// # Arguments
596    ///
597    /// * `timestamp` - The date on which to perform the operation
598    /// * `delta` - The interval to add
599    /// * `tz` - The timezone in which to interpret `timestamp`
600    pub fn add_year_months(
601        timestamp: <Self as ArrowPrimitiveType>::Native,
602        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
603        tz: Tz,
604    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
605        add_year_months::<Self>(timestamp, delta, tz)
606    }
607
608    /// Adds the given IntervalDayTimeType to an arrow TimestampMicrosecondType
609    ///
610    /// # Arguments
611    ///
612    /// * `timestamp` - The date on which to perform the operation
613    /// * `delta` - The interval to add
614    /// * `tz` - The timezone in which to interpret `timestamp`
615    pub fn add_day_time(
616        timestamp: <Self as ArrowPrimitiveType>::Native,
617        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
618        tz: Tz,
619    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
620        add_day_time::<Self>(timestamp, delta, tz)
621    }
622
623    /// Adds the given IntervalMonthDayNanoType to an arrow TimestampMicrosecondType
624    ///
625    /// # Arguments
626    ///
627    /// * `timestamp` - The date on which to perform the operation
628    /// * `delta` - The interval to add
629    /// * `tz` - The timezone in which to interpret `timestamp`
630    pub fn add_month_day_nano(
631        timestamp: <Self as ArrowPrimitiveType>::Native,
632        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
633        tz: Tz,
634    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
635        add_month_day_nano::<Self>(timestamp, delta, tz)
636    }
637
638    /// Subtracts the given IntervalYearMonthType to an arrow TimestampMicrosecondType
639    ///
640    /// # Arguments
641    ///
642    /// * `timestamp` - The date on which to perform the operation
643    /// * `delta` - The interval to add
644    /// * `tz` - The timezone in which to interpret `timestamp`
645    pub fn subtract_year_months(
646        timestamp: <Self as ArrowPrimitiveType>::Native,
647        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
648        tz: Tz,
649    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
650        subtract_year_months::<Self>(timestamp, delta, tz)
651    }
652
653    /// Subtracts the given IntervalDayTimeType to an arrow TimestampMicrosecondType
654    ///
655    /// # Arguments
656    ///
657    /// * `timestamp` - The date on which to perform the operation
658    /// * `delta` - The interval to add
659    /// * `tz` - The timezone in which to interpret `timestamp`
660    pub fn subtract_day_time(
661        timestamp: <Self as ArrowPrimitiveType>::Native,
662        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
663        tz: Tz,
664    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
665        subtract_day_time::<Self>(timestamp, delta, tz)
666    }
667
668    /// Subtracts the given IntervalMonthDayNanoType to an arrow TimestampMicrosecondType
669    ///
670    /// # Arguments
671    ///
672    /// * `timestamp` - The date on which to perform the operation
673    /// * `delta` - The interval to add
674    /// * `tz` - The timezone in which to interpret `timestamp`
675    pub fn subtract_month_day_nano(
676        timestamp: <Self as ArrowPrimitiveType>::Native,
677        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
678        tz: Tz,
679    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
680        subtract_month_day_nano::<Self>(timestamp, delta, tz)
681    }
682}
683
684impl TimestampMillisecondType {
685    /// Adds the given IntervalYearMonthType to an arrow TimestampMillisecondType
686    ///
687    /// # Arguments
688    ///
689    /// * `timestamp` - The date on which to perform the operation
690    /// * `delta` - The interval to add
691    /// * `tz` - The timezone in which to interpret `timestamp`
692    pub fn add_year_months(
693        timestamp: <Self as ArrowPrimitiveType>::Native,
694        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
695        tz: Tz,
696    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
697        add_year_months::<Self>(timestamp, delta, tz)
698    }
699
700    /// Adds the given IntervalDayTimeType to an arrow TimestampMillisecondType
701    ///
702    /// # Arguments
703    ///
704    /// * `timestamp` - The date on which to perform the operation
705    /// * `delta` - The interval to add
706    /// * `tz` - The timezone in which to interpret `timestamp`
707    pub fn add_day_time(
708        timestamp: <Self as ArrowPrimitiveType>::Native,
709        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
710        tz: Tz,
711    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
712        add_day_time::<Self>(timestamp, delta, tz)
713    }
714
715    /// Adds the given IntervalMonthDayNanoType to an arrow TimestampMillisecondType
716    ///
717    /// # Arguments
718    ///
719    /// * `timestamp` - The date on which to perform the operation
720    /// * `delta` - The interval to add
721    /// * `tz` - The timezone in which to interpret `timestamp`
722    pub fn add_month_day_nano(
723        timestamp: <Self as ArrowPrimitiveType>::Native,
724        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
725        tz: Tz,
726    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
727        add_month_day_nano::<Self>(timestamp, delta, tz)
728    }
729
730    /// Subtracts the given IntervalYearMonthType to an arrow TimestampMillisecondType
731    ///
732    /// # Arguments
733    ///
734    /// * `timestamp` - The date on which to perform the operation
735    /// * `delta` - The interval to add
736    /// * `tz` - The timezone in which to interpret `timestamp`
737    pub fn subtract_year_months(
738        timestamp: <Self as ArrowPrimitiveType>::Native,
739        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
740        tz: Tz,
741    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
742        subtract_year_months::<Self>(timestamp, delta, tz)
743    }
744
745    /// Subtracts the given IntervalDayTimeType to an arrow TimestampMillisecondType
746    ///
747    /// # Arguments
748    ///
749    /// * `timestamp` - The date on which to perform the operation
750    /// * `delta` - The interval to add
751    /// * `tz` - The timezone in which to interpret `timestamp`
752    pub fn subtract_day_time(
753        timestamp: <Self as ArrowPrimitiveType>::Native,
754        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
755        tz: Tz,
756    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
757        subtract_day_time::<Self>(timestamp, delta, tz)
758    }
759
760    /// Subtracts the given IntervalMonthDayNanoType to an arrow TimestampMillisecondType
761    ///
762    /// # Arguments
763    ///
764    /// * `timestamp` - The date on which to perform the operation
765    /// * `delta` - The interval to add
766    /// * `tz` - The timezone in which to interpret `timestamp`
767    pub fn subtract_month_day_nano(
768        timestamp: <Self as ArrowPrimitiveType>::Native,
769        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
770        tz: Tz,
771    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
772        subtract_month_day_nano::<Self>(timestamp, delta, tz)
773    }
774}
775
776impl TimestampNanosecondType {
777    /// Adds the given IntervalYearMonthType to an arrow TimestampNanosecondType
778    ///
779    /// # Arguments
780    ///
781    /// * `timestamp` - The date on which to perform the operation
782    /// * `delta` - The interval to add
783    /// * `tz` - The timezone in which to interpret `timestamp`
784    pub fn add_year_months(
785        timestamp: <Self as ArrowPrimitiveType>::Native,
786        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
787        tz: Tz,
788    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
789        add_year_months::<Self>(timestamp, delta, tz)
790    }
791
792    /// Adds the given IntervalDayTimeType to an arrow TimestampNanosecondType
793    ///
794    /// # Arguments
795    ///
796    /// * `timestamp` - The date on which to perform the operation
797    /// * `delta` - The interval to add
798    /// * `tz` - The timezone in which to interpret `timestamp`
799    pub fn add_day_time(
800        timestamp: <Self as ArrowPrimitiveType>::Native,
801        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
802        tz: Tz,
803    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
804        add_day_time::<Self>(timestamp, delta, tz)
805    }
806
807    /// Adds the given IntervalMonthDayNanoType to an arrow TimestampNanosecondType
808    ///
809    /// # Arguments
810    ///
811    /// * `timestamp` - The date on which to perform the operation
812    /// * `delta` - The interval to add
813    /// * `tz` - The timezone in which to interpret `timestamp`
814    pub fn add_month_day_nano(
815        timestamp: <Self as ArrowPrimitiveType>::Native,
816        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
817        tz: Tz,
818    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
819        add_month_day_nano::<Self>(timestamp, delta, tz)
820    }
821
822    /// Subtracts the given IntervalYearMonthType to an arrow TimestampNanosecondType
823    ///
824    /// # Arguments
825    ///
826    /// * `timestamp` - The date on which to perform the operation
827    /// * `delta` - The interval to add
828    /// * `tz` - The timezone in which to interpret `timestamp`
829    pub fn subtract_year_months(
830        timestamp: <Self as ArrowPrimitiveType>::Native,
831        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
832        tz: Tz,
833    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
834        subtract_year_months::<Self>(timestamp, delta, tz)
835    }
836
837    /// Subtracts the given IntervalDayTimeType to an arrow TimestampNanosecondType
838    ///
839    /// # Arguments
840    ///
841    /// * `timestamp` - The date on which to perform the operation
842    /// * `delta` - The interval to add
843    /// * `tz` - The timezone in which to interpret `timestamp`
844    pub fn subtract_day_time(
845        timestamp: <Self as ArrowPrimitiveType>::Native,
846        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
847        tz: Tz,
848    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
849        subtract_day_time::<Self>(timestamp, delta, tz)
850    }
851
852    /// Subtracts the given IntervalMonthDayNanoType to an arrow TimestampNanosecondType
853    ///
854    /// # Arguments
855    ///
856    /// * `timestamp` - The date on which to perform the operation
857    /// * `delta` - The interval to add
858    /// * `tz` - The timezone in which to interpret `timestamp`
859    pub fn subtract_month_day_nano(
860        timestamp: <Self as ArrowPrimitiveType>::Native,
861        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
862        tz: Tz,
863    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
864        subtract_month_day_nano::<Self>(timestamp, delta, tz)
865    }
866}
867
868impl IntervalYearMonthType {
869    /// Creates a IntervalYearMonthType::Native
870    ///
871    /// # Arguments
872    ///
873    /// * `years` - The number of years (+/-) represented in this interval
874    /// * `months` - The number of months (+/-) represented in this interval
875    #[inline]
876    pub fn make_value(
877        years: i32,
878        months: i32,
879    ) -> <IntervalYearMonthType as ArrowPrimitiveType>::Native {
880        years * 12 + months
881    }
882
883    /// Turns a IntervalYearMonthType type into an i32 of months.
884    ///
885    /// This operation is technically a no-op, it is included for comprehensiveness.
886    ///
887    /// # Arguments
888    ///
889    /// * `i` - The IntervalYearMonthType::Native to convert
890    #[inline]
891    pub fn to_months(i: <IntervalYearMonthType as ArrowPrimitiveType>::Native) -> i32 {
892        i
893    }
894}
895
896impl IntervalDayTimeType {
897    /// Creates a IntervalDayTimeType::Native
898    ///
899    /// # Arguments
900    ///
901    /// * `days` - The number of days (+/-) represented in this interval
902    /// * `millis` - The number of milliseconds (+/-) represented in this interval
903    #[inline]
904    pub fn make_value(days: i32, milliseconds: i32) -> IntervalDayTime {
905        IntervalDayTime { days, milliseconds }
906    }
907
908    /// Turns a IntervalDayTimeType into a tuple of (days, milliseconds)
909    ///
910    /// # Arguments
911    ///
912    /// * `i` - The IntervalDayTimeType to convert
913    #[inline]
914    pub fn to_parts(i: IntervalDayTime) -> (i32, i32) {
915        (i.days, i.milliseconds)
916    }
917}
918
919impl IntervalMonthDayNanoType {
920    /// Creates a IntervalMonthDayNanoType::Native
921    ///
922    /// # Arguments
923    ///
924    /// * `months` - The number of months (+/-) represented in this interval
925    /// * `days` - The number of days (+/-) represented in this interval
926    /// * `nanos` - The number of nanoseconds (+/-) represented in this interval
927    #[inline]
928    pub fn make_value(months: i32, days: i32, nanoseconds: i64) -> IntervalMonthDayNano {
929        IntervalMonthDayNano {
930            months,
931            days,
932            nanoseconds,
933        }
934    }
935
936    /// Turns a IntervalMonthDayNanoType into a tuple of (months, days, nanos)
937    ///
938    /// # Arguments
939    ///
940    /// * `i` - The IntervalMonthDayNanoType to convert
941    #[inline]
942    pub fn to_parts(i: IntervalMonthDayNano) -> (i32, i32, i64) {
943        (i.months, i.days, i.nanoseconds)
944    }
945}
946
947impl Date32Type {
948    /// Converts an arrow Date32Type into a chrono::NaiveDate
949    ///
950    /// # Arguments
951    ///
952    /// * `i` - The Date32Type to convert
953    #[deprecated(since = "58.0.0", note = "Use to_naive_date_opt instead.")]
954    pub fn to_naive_date(i: <Date32Type as ArrowPrimitiveType>::Native) -> NaiveDate {
955        Self::to_naive_date_opt(i)
956            .unwrap_or_else(|| panic!("Date32Type::to_naive_date overflowed for date: {i}",))
957    }
958
959    /// Converts an arrow Date32Type into a chrono::NaiveDate
960    ///
961    /// # Arguments
962    ///
963    /// * `i` - The Date32Type to convert
964    ///
965    /// Returns `Some(NaiveDate)` if it fits, `None` otherwise.
966    pub fn to_naive_date_opt(i: <Date32Type as ArrowPrimitiveType>::Native) -> Option<NaiveDate> {
967        let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
968        Duration::try_days(i as i64).and_then(|d| epoch.checked_add_signed(d))
969    }
970
971    /// Converts a chrono::NaiveDate into an arrow Date32Type
972    ///
973    /// # Arguments
974    ///
975    /// * `d` - The NaiveDate to convert
976    pub fn from_naive_date(d: NaiveDate) -> <Date32Type as ArrowPrimitiveType>::Native {
977        let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
978        d.sub(epoch).num_days() as <Date32Type as ArrowPrimitiveType>::Native
979    }
980
981    /// Adds the given IntervalYearMonthType to an arrow Date32Type
982    ///
983    /// # Arguments
984    ///
985    /// * `date` - The date on which to perform the operation
986    /// * `delta` - The interval to add
987    #[deprecated(
988        since = "58.0.0",
989        note = "Use `add_year_months_opt` instead, which returns an Option to handle overflow."
990    )]
991    pub fn add_year_months(
992        date: <Date32Type as ArrowPrimitiveType>::Native,
993        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
994    ) -> <Date32Type as ArrowPrimitiveType>::Native {
995        Self::add_year_months_opt(date, delta).unwrap_or_else(|| {
996            panic!("Date32Type::add_year_months overflowed for date: {date}, delta: {delta}",)
997        })
998    }
999
1000    /// Adds the given IntervalYearMonthType to an arrow Date32Type
1001    ///
1002    /// # Arguments
1003    ///
1004    /// * `date` - The date on which to perform the operation
1005    /// * `delta` - The interval to add
1006    ///
1007    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1008    pub fn add_year_months_opt(
1009        date: <Date32Type as ArrowPrimitiveType>::Native,
1010        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1011    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1012        let prior = Date32Type::to_naive_date_opt(date)?;
1013        let months = IntervalYearMonthType::to_months(delta);
1014        let posterior = add_months_date(prior, months)?;
1015        Some(Date32Type::from_naive_date(posterior))
1016    }
1017
1018    /// Adds the given IntervalDayTimeType to an arrow Date32Type
1019    ///
1020    /// # Arguments
1021    ///
1022    /// * `date` - The date on which to perform the operation
1023    /// * `delta` - The interval to add
1024    #[deprecated(
1025        since = "58.0.0",
1026        note = "Use `add_day_time_opt` instead, which returns an Option to handle overflow."
1027    )]
1028    pub fn add_day_time(
1029        date: <Date32Type as ArrowPrimitiveType>::Native,
1030        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1031    ) -> <Date32Type as ArrowPrimitiveType>::Native {
1032        Self::add_day_time_opt(date, delta).unwrap_or_else(|| {
1033            panic!("Date32Type::add_day_time overflowed for date: {date}, delta: {delta:?}",)
1034        })
1035    }
1036
1037    /// Adds the given IntervalDayTimeType to an arrow Date32Type
1038    ///
1039    /// # Arguments
1040    ///
1041    /// * `date` - The date on which to perform the operation
1042    /// * `delta` - The interval to add
1043    ///
1044    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1045    pub fn add_day_time_opt(
1046        date: <Date32Type as ArrowPrimitiveType>::Native,
1047        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1048    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1049        let (days, ms) = IntervalDayTimeType::to_parts(delta);
1050        let res = Date32Type::to_naive_date_opt(date)?;
1051        let res = res.checked_add_signed(Duration::try_days(days as i64)?)?;
1052        let res = res.checked_add_signed(Duration::try_milliseconds(ms as i64)?)?;
1053        Some(Date32Type::from_naive_date(res))
1054    }
1055
1056    /// Adds the given IntervalMonthDayNanoType to an arrow Date32Type
1057    ///
1058    /// # Arguments
1059    ///
1060    /// * `date` - The date on which to perform the operation
1061    /// * `delta` - The interval to add
1062    #[deprecated(
1063        since = "58.0.0",
1064        note = "Use `add_month_day_nano_opt` instead, which returns an Option to handle overflow."
1065    )]
1066    pub fn add_month_day_nano(
1067        date: <Date32Type as ArrowPrimitiveType>::Native,
1068        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1069    ) -> <Date32Type as ArrowPrimitiveType>::Native {
1070        Self::add_month_day_nano_opt(date, delta).unwrap_or_else(|| {
1071            panic!("Date32Type::add_month_day_nano overflowed for date: {date}, delta: {delta:?}",)
1072        })
1073    }
1074
1075    /// Adds the given IntervalMonthDayNanoType to an arrow Date32Type
1076    ///
1077    /// # Arguments
1078    ///
1079    /// * `date` - The date on which to perform the operation
1080    /// * `delta` - The interval to add
1081    ///
1082    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1083    pub fn add_month_day_nano_opt(
1084        date: <Date32Type as ArrowPrimitiveType>::Native,
1085        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1086    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1087        let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
1088        let res = Date32Type::to_naive_date_opt(date)?;
1089        let res = add_months_date(res, months)?;
1090        let res = res.checked_add_signed(Duration::try_days(days as i64)?)?;
1091        let res = res.checked_add_signed(Duration::nanoseconds(nanos))?;
1092        Some(Date32Type::from_naive_date(res))
1093    }
1094
1095    /// Subtract the given IntervalYearMonthType to an arrow Date32Type
1096    ///
1097    /// # Arguments
1098    ///
1099    /// * `date` - The date on which to perform the operation
1100    /// * `delta` - The interval to subtract
1101    #[deprecated(
1102        since = "58.0.0",
1103        note = "Use `subtract_year_months_opt` instead, which returns an Option to handle overflow."
1104    )]
1105    pub fn subtract_year_months(
1106        date: <Date32Type as ArrowPrimitiveType>::Native,
1107        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1108    ) -> <Date32Type as ArrowPrimitiveType>::Native {
1109        Self::subtract_year_months_opt(date, delta).unwrap_or_else(|| {
1110            panic!("Date32Type::subtract_year_months overflowed for date: {date}, delta: {delta}",)
1111        })
1112    }
1113
1114    /// Subtract the given IntervalYearMonthType to an arrow Date32Type
1115    ///
1116    /// # Arguments
1117    ///
1118    /// * `date` - The date on which to perform the operation
1119    /// * `delta` - The interval to subtract
1120    ///
1121    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1122    pub fn subtract_year_months_opt(
1123        date: <Date32Type as ArrowPrimitiveType>::Native,
1124        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1125    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1126        let prior = Date32Type::to_naive_date_opt(date)?;
1127        let months = IntervalYearMonthType::to_months(-delta);
1128        let posterior = add_months_date(prior, months)?;
1129        Some(Date32Type::from_naive_date(posterior))
1130    }
1131
1132    /// Subtract the given IntervalDayTimeType to an arrow Date32Type
1133    ///
1134    /// # Arguments
1135    ///
1136    /// * `date` - The date on which to perform the operation
1137    /// * `delta` - The interval to subtract
1138    #[deprecated(
1139        since = "58.0.0",
1140        note = "Use `subtract_day_time_opt` instead, which returns an Option to handle overflow."
1141    )]
1142    pub fn subtract_day_time(
1143        date: <Date32Type as ArrowPrimitiveType>::Native,
1144        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1145    ) -> <Date32Type as ArrowPrimitiveType>::Native {
1146        Self::subtract_day_time_opt(date, delta).unwrap_or_else(|| {
1147            panic!("Date32Type::subtract_day_time overflowed for date: {date}, delta: {delta:?}",)
1148        })
1149    }
1150
1151    /// Subtract the given IntervalDayTimeType to an arrow Date32Type
1152    ///
1153    /// # Arguments
1154    ///
1155    /// * `date` - The date on which to perform the operation
1156    /// * `delta` - The interval to subtract
1157    ///
1158    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1159    pub fn subtract_day_time_opt(
1160        date: <Date32Type as ArrowPrimitiveType>::Native,
1161        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1162    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1163        let (days, ms) = IntervalDayTimeType::to_parts(delta);
1164        let res = Date32Type::to_naive_date_opt(date)?;
1165        let res = res.checked_sub_signed(Duration::try_days(days as i64)?)?;
1166        let res = res.checked_sub_signed(Duration::try_milliseconds(ms as i64)?)?;
1167        Some(Date32Type::from_naive_date(res))
1168    }
1169
1170    /// Subtract the given IntervalMonthDayNanoType to an arrow Date32Type
1171    ///
1172    /// # Arguments
1173    ///
1174    /// * `date` - The date on which to perform the operation
1175    /// * `delta` - The interval to subtract
1176    #[deprecated(
1177        since = "58.0.0",
1178        note = "Use `subtract_month_day_nano_opt` instead, which returns an Option to handle overflow."
1179    )]
1180    pub fn subtract_month_day_nano(
1181        date: <Date32Type as ArrowPrimitiveType>::Native,
1182        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1183    ) -> <Date32Type as ArrowPrimitiveType>::Native {
1184        Self::subtract_month_day_nano_opt(date, delta).unwrap_or_else(|| {
1185            panic!(
1186                "Date32Type::subtract_month_day_nano overflowed for date: {date}, delta: {delta:?}",
1187            )
1188        })
1189    }
1190
1191    /// Subtract the given IntervalMonthDayNanoType to an arrow Date32Type
1192    ///
1193    /// # Arguments
1194    ///
1195    /// * `date` - The date on which to perform the operation
1196    /// * `delta` - The interval to subtract
1197    ///
1198    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1199    pub fn subtract_month_day_nano_opt(
1200        date: <Date32Type as ArrowPrimitiveType>::Native,
1201        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1202    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1203        let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
1204        let res = Date32Type::to_naive_date_opt(date)?;
1205        let res = add_months_date(res, -months)?;
1206        let res = res.checked_sub_signed(Duration::try_days(days as i64)?)?;
1207        let res = res.checked_sub_signed(Duration::nanoseconds(nanos))?;
1208        Some(Date32Type::from_naive_date(res))
1209    }
1210}
1211
1212impl Date64Type {
1213    /// Converts an arrow Date64Type into a chrono::NaiveDate
1214    ///
1215    /// # Arguments
1216    ///
1217    /// * `i` - The Date64Type to convert
1218    #[deprecated(since = "56.0.0", note = "Use to_naive_date_opt instead.")]
1219    pub fn to_naive_date(i: <Date64Type as ArrowPrimitiveType>::Native) -> NaiveDate {
1220        Self::to_naive_date_opt(i)
1221            .unwrap_or_else(|| panic!("Date64Type::to_naive_date overflowed for date: {i}",))
1222    }
1223
1224    /// Converts an arrow Date64Type into a chrono::NaiveDateTime if it fits in the range that chrono::NaiveDateTime can represent.
1225    /// Returns `None` if the calculation would overflow or underflow.
1226    ///
1227    /// This function is able to handle dates ranging between 1677-09-21 (-9,223,372,800,000) and 2262-04-11 (9,223,286,400,000).
1228    ///
1229    /// # Arguments
1230    ///
1231    /// * `i` - The Date64Type to convert
1232    ///
1233    /// Returns `Some(NaiveDateTime)` if it fits, `None` otherwise.
1234    pub fn to_naive_date_opt(i: <Date64Type as ArrowPrimitiveType>::Native) -> Option<NaiveDate> {
1235        let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
1236        Duration::try_milliseconds(i).and_then(|d| epoch.checked_add_signed(d))
1237    }
1238
1239    /// Converts a chrono::NaiveDate into an arrow Date64Type
1240    ///
1241    /// # Arguments
1242    ///
1243    /// * `d` - The NaiveDate to convert
1244    pub fn from_naive_date(d: NaiveDate) -> <Date64Type as ArrowPrimitiveType>::Native {
1245        let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
1246        d.sub(epoch).num_milliseconds() as <Date64Type as ArrowPrimitiveType>::Native
1247    }
1248
1249    /// Adds the given IntervalYearMonthType to an arrow Date64Type
1250    ///
1251    /// # Arguments
1252    ///
1253    /// * `date` - The date on which to perform the operation
1254    /// * `delta` - The interval to add
1255    #[deprecated(
1256        since = "56.0.0",
1257        note = "Use `add_year_months_opt` instead, which returns an Option to handle overflow."
1258    )]
1259    pub fn add_year_months(
1260        date: <Date64Type as ArrowPrimitiveType>::Native,
1261        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1262    ) -> <Date64Type as ArrowPrimitiveType>::Native {
1263        Self::add_year_months_opt(date, delta).unwrap_or_else(|| {
1264            panic!("Date64Type::add_year_months overflowed for date: {date}, delta: {delta}",)
1265        })
1266    }
1267
1268    /// Adds the given IntervalYearMonthType to an arrow Date64Type
1269    ///
1270    /// # Arguments
1271    ///
1272    /// * `date` - The date on which to perform the operation
1273    /// * `delta` - The interval to add
1274    ///
1275    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1276    pub fn add_year_months_opt(
1277        date: <Date64Type as ArrowPrimitiveType>::Native,
1278        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1279    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1280        let prior = Date64Type::to_naive_date_opt(date)?;
1281        let months = IntervalYearMonthType::to_months(delta);
1282        let posterior = add_months_date(prior, months)?;
1283        Some(Date64Type::from_naive_date(posterior))
1284    }
1285
1286    /// Adds the given IntervalDayTimeType to an arrow Date64Type
1287    ///
1288    /// # Arguments
1289    ///
1290    /// * `date` - The date on which to perform the operation
1291    /// * `delta` - The interval to add
1292    #[deprecated(
1293        since = "56.0.0",
1294        note = "Use `add_day_time_opt` instead, which returns an Option to handle overflow."
1295    )]
1296    pub fn add_day_time(
1297        date: <Date64Type as ArrowPrimitiveType>::Native,
1298        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1299    ) -> <Date64Type as ArrowPrimitiveType>::Native {
1300        Self::add_day_time_opt(date, delta).unwrap_or_else(|| {
1301            panic!("Date64Type::add_day_time overflowed for date: {date}, delta: {delta:?}",)
1302        })
1303    }
1304
1305    /// Adds the given IntervalDayTimeType to an arrow Date64Type
1306    ///
1307    /// # Arguments
1308    ///
1309    /// * `date` - The date on which to perform the operation
1310    /// * `delta` - The interval to add
1311    ///
1312    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1313    pub fn add_day_time_opt(
1314        date: <Date64Type as ArrowPrimitiveType>::Native,
1315        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1316    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1317        let (days, ms) = IntervalDayTimeType::to_parts(delta);
1318        let res = Date64Type::to_naive_date_opt(date)?;
1319        let res = res.checked_add_signed(Duration::try_days(days as i64)?)?;
1320        let res = res.checked_add_signed(Duration::try_milliseconds(ms as i64)?)?;
1321        Some(Date64Type::from_naive_date(res))
1322    }
1323
1324    /// Adds the given IntervalMonthDayNanoType to an arrow Date64Type
1325    ///
1326    /// # Arguments
1327    ///
1328    /// * `date` - The date on which to perform the operation
1329    /// * `delta` - The interval to add
1330    #[deprecated(
1331        since = "56.0.0",
1332        note = "Use `add_month_day_nano_opt` instead, which returns an Option to handle overflow."
1333    )]
1334    pub fn add_month_day_nano(
1335        date: <Date64Type as ArrowPrimitiveType>::Native,
1336        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1337    ) -> <Date64Type as ArrowPrimitiveType>::Native {
1338        Self::add_month_day_nano_opt(date, delta).unwrap_or_else(|| {
1339            panic!("Date64Type::add_month_day_nano overflowed for date: {date}, delta: {delta:?}",)
1340        })
1341    }
1342
1343    /// Adds the given IntervalMonthDayNanoType to an arrow Date64Type
1344    ///
1345    /// # Arguments
1346    ///
1347    /// * `date` - The date on which to perform the operation
1348    /// * `delta` - The interval to add
1349    ///
1350    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1351    pub fn add_month_day_nano_opt(
1352        date: <Date64Type as ArrowPrimitiveType>::Native,
1353        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1354    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1355        let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
1356        let res = Date64Type::to_naive_date_opt(date)?;
1357        let res = add_months_date(res, months)?;
1358        let res = res.checked_add_signed(Duration::try_days(days as i64)?)?;
1359        let res = res.checked_add_signed(Duration::nanoseconds(nanos))?;
1360        Some(Date64Type::from_naive_date(res))
1361    }
1362
1363    /// Subtract the given IntervalYearMonthType to an arrow Date64Type
1364    ///
1365    /// # Arguments
1366    ///
1367    /// * `date` - The date on which to perform the operation
1368    /// * `delta` - The interval to subtract
1369    #[deprecated(
1370        since = "56.0.0",
1371        note = "Use `subtract_year_months_opt` instead, which returns an Option to handle overflow."
1372    )]
1373    pub fn subtract_year_months(
1374        date: <Date64Type as ArrowPrimitiveType>::Native,
1375        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1376    ) -> <Date64Type as ArrowPrimitiveType>::Native {
1377        Self::subtract_year_months_opt(date, delta).unwrap_or_else(|| {
1378            panic!("Date64Type::subtract_year_months overflowed for date: {date}, delta: {delta}",)
1379        })
1380    }
1381
1382    /// Subtract the given IntervalYearMonthType to an arrow Date64Type
1383    ///
1384    /// # Arguments
1385    ///
1386    /// * `date` - The date on which to perform the operation
1387    /// * `delta` - The interval to subtract
1388    ///
1389    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1390    pub fn subtract_year_months_opt(
1391        date: <Date64Type as ArrowPrimitiveType>::Native,
1392        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1393    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1394        let prior = Date64Type::to_naive_date_opt(date)?;
1395        let months = IntervalYearMonthType::to_months(-delta);
1396        let posterior = add_months_date(prior, months)?;
1397        Some(Date64Type::from_naive_date(posterior))
1398    }
1399
1400    /// Subtract the given IntervalDayTimeType to an arrow Date64Type
1401    ///
1402    /// # Arguments
1403    ///
1404    /// * `date` - The date on which to perform the operation
1405    /// * `delta` - The interval to subtract
1406    #[deprecated(
1407        since = "56.0.0",
1408        note = "Use `subtract_day_time_opt` instead, which returns an Option to handle overflow."
1409    )]
1410    pub fn subtract_day_time(
1411        date: <Date64Type as ArrowPrimitiveType>::Native,
1412        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1413    ) -> <Date64Type as ArrowPrimitiveType>::Native {
1414        Self::subtract_day_time_opt(date, delta).unwrap_or_else(|| {
1415            panic!("Date64Type::subtract_day_time overflowed for date: {date}, delta: {delta:?}",)
1416        })
1417    }
1418
1419    /// Subtract the given IntervalDayTimeType to an arrow Date64Type
1420    ///
1421    /// # Arguments
1422    ///
1423    /// * `date` - The date on which to perform the operation
1424    /// * `delta` - The interval to subtract
1425    ///
1426    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1427    pub fn subtract_day_time_opt(
1428        date: <Date64Type as ArrowPrimitiveType>::Native,
1429        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1430    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1431        let (days, ms) = IntervalDayTimeType::to_parts(delta);
1432        let res = Date64Type::to_naive_date_opt(date)?;
1433        let res = res.checked_sub_signed(Duration::try_days(days as i64)?)?;
1434        let res = res.checked_sub_signed(Duration::try_milliseconds(ms as i64)?)?;
1435        Some(Date64Type::from_naive_date(res))
1436    }
1437
1438    /// Subtract the given IntervalMonthDayNanoType to an arrow Date64Type
1439    ///
1440    /// # Arguments
1441    ///
1442    /// * `date` - The date on which to perform the operation
1443    /// * `delta` - The interval to subtract
1444    #[deprecated(
1445        since = "56.0.0",
1446        note = "Use `subtract_month_day_nano_opt` instead, which returns an Option to handle overflow."
1447    )]
1448    pub fn subtract_month_day_nano(
1449        date: <Date64Type as ArrowPrimitiveType>::Native,
1450        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1451    ) -> <Date64Type as ArrowPrimitiveType>::Native {
1452        Self::subtract_month_day_nano_opt(date, delta).unwrap_or_else(|| {
1453            panic!(
1454                "Date64Type::subtract_month_day_nano overflowed for date: {date}, delta: {delta:?}",
1455            )
1456        })
1457    }
1458
1459    /// Subtract the given IntervalMonthDayNanoType to an arrow Date64Type
1460    ///
1461    /// # Arguments
1462    ///
1463    /// * `date` - The date on which to perform the operation
1464    /// * `delta` - The interval to subtract
1465    ///
1466    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1467    pub fn subtract_month_day_nano_opt(
1468        date: <Date64Type as ArrowPrimitiveType>::Native,
1469        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1470    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1471        let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
1472        let res = Date64Type::to_naive_date_opt(date)?;
1473        let res = add_months_date(res, -months)?;
1474        let res = res.checked_sub_signed(Duration::try_days(days as i64)?)?;
1475        let res = res.checked_sub_signed(Duration::nanoseconds(nanos))?;
1476        Some(Date64Type::from_naive_date(res))
1477    }
1478}
1479
1480/// Crate private types for Decimal Arrays
1481///
1482/// Not intended to be used outside this crate
1483mod decimal {
1484    use super::*;
1485
1486    pub trait DecimalTypeSealed {}
1487    impl DecimalTypeSealed for Decimal32Type {}
1488    impl DecimalTypeSealed for Decimal64Type {}
1489    impl DecimalTypeSealed for Decimal128Type {}
1490    impl DecimalTypeSealed for Decimal256Type {}
1491}
1492
1493/// A trait over the decimal types, used by [`PrimitiveArray`] to provide a generic
1494/// implementation across the various decimal types
1495///
1496/// Implemented by [`Decimal32Type`], [`Decimal64Type`], [`Decimal128Type`] and [`Decimal256Type`]
1497/// for [`Decimal32Array`], [`Decimal64Array`], [`Decimal128Array`] and [`Decimal256Array`] respectively
1498///
1499/// [`PrimitiveArray`]: crate::array::PrimitiveArray
1500/// [`Decimal32Array`]: crate::array::Decimal32Array
1501/// [`Decimal64Array`]: crate::array::Decimal64Array
1502/// [`Decimal128Array`]: crate::array::Decimal128Array
1503/// [`Decimal256Array`]: crate::array::Decimal256Array
1504pub trait DecimalType:
1505    'static + Send + Sync + ArrowPrimitiveType + decimal::DecimalTypeSealed
1506{
1507    /// Width of the type
1508    const BYTE_LENGTH: usize;
1509    /// Maximum number of significant digits
1510    const MAX_PRECISION: u8;
1511    /// Maximum no of digits after the decimal point (note the scale can be negative)
1512    const MAX_SCALE: i8;
1513    /// The maximum value for each precision in `0..=MAX_PRECISION`: [0, 9, 99, ...]
1514    const MAX_FOR_EACH_PRECISION: &'static [Self::Native];
1515    /// fn to create its [`DataType`]
1516    const TYPE_CONSTRUCTOR: fn(u8, i8) -> DataType;
1517    /// Default values for [`DataType`]
1518    const DEFAULT_TYPE: DataType;
1519
1520    /// "Decimal32", "Decimal64", "Decimal128" or "Decimal256", for use in error messages
1521    const PREFIX: &'static str;
1522
1523    /// Formats the decimal value with the provided precision and scale
1524    fn format_decimal(value: Self::Native, precision: u8, scale: i8) -> String;
1525
1526    /// Validates that `value` contains no more than `precision` decimal digits
1527    fn validate_decimal_precision(
1528        value: Self::Native,
1529        precision: u8,
1530        scale: i8,
1531    ) -> Result<(), ArrowError>;
1532
1533    /// Determines whether `value` contains no more than `precision` decimal digits
1534    fn is_valid_decimal_precision(value: Self::Native, precision: u8) -> bool;
1535}
1536
1537/// Validate that `precision` and `scale` are valid for `T`
1538///
1539/// Returns an Error if:
1540/// - `precision` is zero
1541/// - `precision` is larger than `T:MAX_PRECISION`
1542/// - `scale` is larger than `T::MAX_SCALE`
1543/// - `scale` is > `precision`
1544pub fn validate_decimal_precision_and_scale<T: DecimalType>(
1545    precision: u8,
1546    scale: i8,
1547) -> Result<(), ArrowError> {
1548    if precision == 0 {
1549        return Err(ArrowError::InvalidArgumentError(format!(
1550            "precision cannot be 0, has to be between [1, {}]",
1551            T::MAX_PRECISION
1552        )));
1553    }
1554    if precision > T::MAX_PRECISION {
1555        return Err(ArrowError::InvalidArgumentError(format!(
1556            "precision {} is greater than max {}",
1557            precision,
1558            T::MAX_PRECISION
1559        )));
1560    }
1561    if scale > T::MAX_SCALE {
1562        return Err(ArrowError::InvalidArgumentError(format!(
1563            "scale {} is greater than max {}",
1564            scale,
1565            T::MAX_SCALE
1566        )));
1567    }
1568    if scale > 0 && scale as u8 > precision {
1569        return Err(ArrowError::InvalidArgumentError(format!(
1570            "scale {scale} is greater than precision {precision}"
1571        )));
1572    }
1573
1574    Ok(())
1575}
1576
1577/// The decimal type for a Decimal32Array
1578#[derive(Debug)]
1579pub struct Decimal32Type {}
1580
1581impl DecimalType for Decimal32Type {
1582    const BYTE_LENGTH: usize = 4;
1583    const MAX_PRECISION: u8 = DECIMAL32_MAX_PRECISION;
1584    const MAX_SCALE: i8 = DECIMAL32_MAX_SCALE;
1585    const MAX_FOR_EACH_PRECISION: &'static [i32] =
1586        &arrow_data::decimal::MAX_DECIMAL32_FOR_EACH_PRECISION;
1587    const TYPE_CONSTRUCTOR: fn(u8, i8) -> DataType = DataType::Decimal32;
1588    const DEFAULT_TYPE: DataType =
1589        DataType::Decimal32(DECIMAL32_MAX_PRECISION, DECIMAL32_DEFAULT_SCALE);
1590    const PREFIX: &'static str = "Decimal32";
1591
1592    fn format_decimal(value: Self::Native, precision: u8, scale: i8) -> String {
1593        format_decimal_str(&value.to_string(), precision as usize, scale)
1594    }
1595
1596    fn validate_decimal_precision(num: i32, precision: u8, scale: i8) -> Result<(), ArrowError> {
1597        validate_decimal32_precision(num, precision, scale)
1598    }
1599
1600    fn is_valid_decimal_precision(value: Self::Native, precision: u8) -> bool {
1601        is_validate_decimal32_precision(value, precision)
1602    }
1603}
1604
1605impl ArrowPrimitiveType for Decimal32Type {
1606    type Native = i32;
1607
1608    const DATA_TYPE: DataType = <Self as DecimalType>::DEFAULT_TYPE;
1609}
1610
1611impl primitive::PrimitiveTypeSealed for Decimal32Type {}
1612
1613/// The decimal type for a Decimal64Array
1614#[derive(Debug)]
1615pub struct Decimal64Type {}
1616
1617impl DecimalType for Decimal64Type {
1618    const BYTE_LENGTH: usize = 8;
1619    const MAX_PRECISION: u8 = DECIMAL64_MAX_PRECISION;
1620    const MAX_SCALE: i8 = DECIMAL64_MAX_SCALE;
1621    const MAX_FOR_EACH_PRECISION: &'static [i64] =
1622        &arrow_data::decimal::MAX_DECIMAL64_FOR_EACH_PRECISION;
1623    const TYPE_CONSTRUCTOR: fn(u8, i8) -> DataType = DataType::Decimal64;
1624    const DEFAULT_TYPE: DataType =
1625        DataType::Decimal64(DECIMAL64_MAX_PRECISION, DECIMAL64_DEFAULT_SCALE);
1626    const PREFIX: &'static str = "Decimal64";
1627
1628    fn format_decimal(value: Self::Native, precision: u8, scale: i8) -> String {
1629        format_decimal_str(&value.to_string(), precision as usize, scale)
1630    }
1631
1632    fn validate_decimal_precision(num: i64, precision: u8, scale: i8) -> Result<(), ArrowError> {
1633        validate_decimal64_precision(num, precision, scale)
1634    }
1635
1636    fn is_valid_decimal_precision(value: Self::Native, precision: u8) -> bool {
1637        is_validate_decimal64_precision(value, precision)
1638    }
1639}
1640
1641impl ArrowPrimitiveType for Decimal64Type {
1642    type Native = i64;
1643
1644    const DATA_TYPE: DataType = <Self as DecimalType>::DEFAULT_TYPE;
1645}
1646
1647impl primitive::PrimitiveTypeSealed for Decimal64Type {}
1648
1649/// The decimal type for a Decimal128Array
1650#[derive(Debug)]
1651pub struct Decimal128Type {}
1652
1653impl DecimalType for Decimal128Type {
1654    const BYTE_LENGTH: usize = 16;
1655    const MAX_PRECISION: u8 = DECIMAL128_MAX_PRECISION;
1656    const MAX_SCALE: i8 = DECIMAL128_MAX_SCALE;
1657    const MAX_FOR_EACH_PRECISION: &'static [i128] =
1658        &arrow_data::decimal::MAX_DECIMAL128_FOR_EACH_PRECISION;
1659    const TYPE_CONSTRUCTOR: fn(u8, i8) -> DataType = DataType::Decimal128;
1660    const DEFAULT_TYPE: DataType =
1661        DataType::Decimal128(DECIMAL128_MAX_PRECISION, DECIMAL_DEFAULT_SCALE);
1662    const PREFIX: &'static str = "Decimal128";
1663
1664    fn format_decimal(value: Self::Native, precision: u8, scale: i8) -> String {
1665        format_decimal_str(&value.to_string(), precision as usize, scale)
1666    }
1667
1668    fn validate_decimal_precision(num: i128, precision: u8, scale: i8) -> Result<(), ArrowError> {
1669        validate_decimal_precision(num, precision, scale)
1670    }
1671
1672    fn is_valid_decimal_precision(value: Self::Native, precision: u8) -> bool {
1673        is_validate_decimal_precision(value, precision)
1674    }
1675}
1676
1677impl ArrowPrimitiveType for Decimal128Type {
1678    type Native = i128;
1679
1680    const DATA_TYPE: DataType = <Self as DecimalType>::DEFAULT_TYPE;
1681}
1682
1683impl primitive::PrimitiveTypeSealed for Decimal128Type {}
1684
1685/// The decimal type for a Decimal256Array
1686#[derive(Debug)]
1687pub struct Decimal256Type {}
1688
1689impl DecimalType for Decimal256Type {
1690    const BYTE_LENGTH: usize = 32;
1691    const MAX_PRECISION: u8 = DECIMAL256_MAX_PRECISION;
1692    const MAX_SCALE: i8 = DECIMAL256_MAX_SCALE;
1693    const MAX_FOR_EACH_PRECISION: &'static [i256] =
1694        &arrow_data::decimal::MAX_DECIMAL256_FOR_EACH_PRECISION;
1695    const TYPE_CONSTRUCTOR: fn(u8, i8) -> DataType = DataType::Decimal256;
1696    const DEFAULT_TYPE: DataType =
1697        DataType::Decimal256(DECIMAL256_MAX_PRECISION, DECIMAL_DEFAULT_SCALE);
1698    const PREFIX: &'static str = "Decimal256";
1699
1700    fn format_decimal(value: Self::Native, precision: u8, scale: i8) -> String {
1701        format_decimal_str(&value.to_string(), precision as usize, scale)
1702    }
1703
1704    fn validate_decimal_precision(num: i256, precision: u8, scale: i8) -> Result<(), ArrowError> {
1705        validate_decimal256_precision(num, precision, scale)
1706    }
1707
1708    fn is_valid_decimal_precision(value: Self::Native, precision: u8) -> bool {
1709        is_validate_decimal256_precision(value, precision)
1710    }
1711}
1712
1713impl ArrowPrimitiveType for Decimal256Type {
1714    type Native = i256;
1715
1716    const DATA_TYPE: DataType = <Self as DecimalType>::DEFAULT_TYPE;
1717}
1718
1719impl primitive::PrimitiveTypeSealed for Decimal256Type {}
1720
1721/// Crate private types for Byte Arrays
1722///
1723/// Not intended to be used outside this crate
1724pub(crate) mod bytes {
1725    use super::*;
1726
1727    pub trait ByteArrayTypeSealed {}
1728    impl<O: OffsetSizeTrait> ByteArrayTypeSealed for GenericStringType<O> {}
1729    impl<O: OffsetSizeTrait> ByteArrayTypeSealed for GenericBinaryType<O> {}
1730
1731    pub trait ByteArrayNativeType: std::fmt::Debug + Send + Sync {
1732        fn from_bytes_checked(b: &[u8]) -> Option<&Self>;
1733
1734        /// # Safety
1735        ///
1736        /// `b` must be a valid byte sequence for `Self`
1737        unsafe fn from_bytes_unchecked(b: &[u8]) -> &Self;
1738    }
1739
1740    impl ByteArrayNativeType for [u8] {
1741        #[inline]
1742        fn from_bytes_checked(b: &[u8]) -> Option<&Self> {
1743            Some(b)
1744        }
1745
1746        #[inline]
1747        unsafe fn from_bytes_unchecked(b: &[u8]) -> &Self {
1748            b
1749        }
1750    }
1751
1752    impl ByteArrayNativeType for str {
1753        #[inline]
1754        fn from_bytes_checked(b: &[u8]) -> Option<&Self> {
1755            std::str::from_utf8(b).ok()
1756        }
1757
1758        #[inline]
1759        unsafe fn from_bytes_unchecked(b: &[u8]) -> &Self {
1760            unsafe { std::str::from_utf8_unchecked(b) }
1761        }
1762    }
1763}
1764
1765/// A trait over the variable-size byte array types
1766///
1767/// See [Variable Size Binary Layout](https://arrow.apache.org/docs/format/Columnar.html#variable-size-binary-layout)
1768pub trait ByteArrayType: 'static + Send + Sync + bytes::ByteArrayTypeSealed {
1769    /// Type of offset i.e i32/i64
1770    type Offset: OffsetSizeTrait;
1771    /// Type for representing its equivalent rust type i.e
1772    /// Utf8Array will have native type has &str
1773    /// BinaryArray will have type as [u8]
1774    type Native: bytes::ByteArrayNativeType + AsRef<Self::Native> + AsRef<[u8]> + ?Sized;
1775
1776    /// "Binary" or "String", for use in error messages
1777    const PREFIX: &'static str;
1778
1779    /// Datatype of array elements
1780    const DATA_TYPE: DataType;
1781
1782    /// Verifies that every consecutive pair of `offsets` denotes a valid slice of `values`
1783    fn validate(offsets: &OffsetBuffer<Self::Offset>, values: &Buffer) -> Result<(), ArrowError>;
1784}
1785
1786/// [`ByteArrayType`] for string arrays
1787pub struct GenericStringType<O: OffsetSizeTrait> {
1788    phantom: PhantomData<O>,
1789}
1790
1791impl<O: OffsetSizeTrait> ByteArrayType for GenericStringType<O> {
1792    type Offset = O;
1793    type Native = str;
1794    const PREFIX: &'static str = "String";
1795
1796    const DATA_TYPE: DataType = if O::IS_LARGE {
1797        DataType::LargeUtf8
1798    } else {
1799        DataType::Utf8
1800    };
1801
1802    fn validate(offsets: &OffsetBuffer<Self::Offset>, values: &Buffer) -> Result<(), ArrowError> {
1803        // Verify that the slice as a whole is valid UTF-8
1804        let validated = std::str::from_utf8(values).map_err(|e| {
1805            ArrowError::InvalidArgumentError(format!("Encountered non UTF-8 data: {e}"))
1806        })?;
1807
1808        // Verify each offset is at a valid character boundary in this UTF-8 array
1809        for offset in offsets.iter() {
1810            let o = offset.as_usize();
1811            if !validated.is_char_boundary(o) {
1812                if o < validated.len() {
1813                    return Err(ArrowError::InvalidArgumentError(format!(
1814                        "Split UTF-8 codepoint at offset {o}"
1815                    )));
1816                }
1817                return Err(ArrowError::InvalidArgumentError(format!(
1818                    "Offset of {o} exceeds length of values {}",
1819                    validated.len()
1820                )));
1821            }
1822        }
1823        Ok(())
1824    }
1825}
1826
1827/// An arrow utf8 array with i32 offsets
1828pub type Utf8Type = GenericStringType<i32>;
1829/// An arrow utf8 array with i64 offsets
1830pub type LargeUtf8Type = GenericStringType<i64>;
1831
1832/// [`ByteArrayType`] for binary arrays
1833pub struct GenericBinaryType<O: OffsetSizeTrait> {
1834    phantom: PhantomData<O>,
1835}
1836
1837impl<O: OffsetSizeTrait> ByteArrayType for GenericBinaryType<O> {
1838    type Offset = O;
1839    type Native = [u8];
1840    const PREFIX: &'static str = "Binary";
1841
1842    const DATA_TYPE: DataType = if O::IS_LARGE {
1843        DataType::LargeBinary
1844    } else {
1845        DataType::Binary
1846    };
1847
1848    fn validate(offsets: &OffsetBuffer<Self::Offset>, values: &Buffer) -> Result<(), ArrowError> {
1849        // offsets are guaranteed to be monotonically increasing and non-empty
1850        let max_offset = offsets.last().unwrap().as_usize();
1851        if values.len() < max_offset {
1852            return Err(ArrowError::InvalidArgumentError(format!(
1853                "Maximum offset of {max_offset} is larger than values of length {}",
1854                values.len()
1855            )));
1856        }
1857        Ok(())
1858    }
1859}
1860
1861/// An arrow binary array with i32 offsets
1862pub type BinaryType = GenericBinaryType<i32>;
1863/// An arrow binary array with i64 offsets
1864pub type LargeBinaryType = GenericBinaryType<i64>;
1865
1866mod byte_view {
1867    use crate::types::{BinaryViewType, StringViewType};
1868
1869    pub trait Sealed: Send + Sync {}
1870    impl Sealed for StringViewType {}
1871    impl Sealed for BinaryViewType {}
1872}
1873
1874/// A trait over the variable length bytes view array types
1875pub trait ByteViewType: byte_view::Sealed + 'static + PartialEq + Send + Sync {
1876    /// If element in array is utf8 encoded string.
1877    const IS_UTF8: bool;
1878
1879    /// Datatype of array elements
1880    const DATA_TYPE: DataType = if Self::IS_UTF8 {
1881        DataType::Utf8View
1882    } else {
1883        DataType::BinaryView
1884    };
1885
1886    /// "Binary" or "String", for use in displayed or error messages
1887    const PREFIX: &'static str;
1888
1889    /// Type for representing its equivalent rust type i.e
1890    /// Utf8Array will have native type has &str
1891    /// BinaryArray will have type as [u8]
1892    type Native: bytes::ByteArrayNativeType + AsRef<Self::Native> + AsRef<[u8]> + ?Sized;
1893
1894    /// Type for owned corresponding to `Native`
1895    type Owned: Debug + Clone + Sync + Send + AsRef<Self::Native>;
1896
1897    /// Verifies that the provided buffers are valid for this array type
1898    fn validate(views: &[u128], buffers: &[Buffer]) -> Result<(), ArrowError>;
1899}
1900
1901/// [`ByteViewType`] for string arrays
1902#[derive(PartialEq)]
1903pub struct StringViewType {}
1904
1905impl ByteViewType for StringViewType {
1906    const IS_UTF8: bool = true;
1907    const PREFIX: &'static str = "String";
1908
1909    type Native = str;
1910    type Owned = String;
1911
1912    fn validate(views: &[u128], buffers: &[Buffer]) -> Result<(), ArrowError> {
1913        validate_string_view(views, buffers)
1914    }
1915}
1916
1917/// [`BinaryViewType`] for string arrays
1918#[derive(PartialEq)]
1919pub struct BinaryViewType {}
1920
1921impl ByteViewType for BinaryViewType {
1922    const IS_UTF8: bool = false;
1923    const PREFIX: &'static str = "Binary";
1924    type Native = [u8];
1925    type Owned = Vec<u8>;
1926
1927    fn validate(views: &[u128], buffers: &[Buffer]) -> Result<(), ArrowError> {
1928        validate_binary_view(views, buffers)
1929    }
1930}
1931
1932#[cfg(test)]
1933mod tests {
1934    use super::*;
1935    use arrow_data::{BufferSpec, layout};
1936    use chrono::DateTime;
1937
1938    #[test]
1939    fn month_day_nano_should_roundtrip() {
1940        let value = IntervalMonthDayNanoType::make_value(1, 2, 3);
1941        assert_eq!(IntervalMonthDayNanoType::to_parts(value), (1, 2, 3));
1942    }
1943
1944    #[test]
1945    fn month_day_nano_should_roundtrip_neg() {
1946        let value = IntervalMonthDayNanoType::make_value(-1, -2, -3);
1947        assert_eq!(IntervalMonthDayNanoType::to_parts(value), (-1, -2, -3));
1948    }
1949
1950    #[test]
1951    fn day_time_should_roundtrip() {
1952        let value = IntervalDayTimeType::make_value(1, 2);
1953        assert_eq!(IntervalDayTimeType::to_parts(value), (1, 2));
1954    }
1955
1956    #[test]
1957    fn day_time_should_roundtrip_neg() {
1958        let value = IntervalDayTimeType::make_value(-1, -2);
1959        assert_eq!(IntervalDayTimeType::to_parts(value), (-1, -2));
1960    }
1961
1962    #[test]
1963    fn year_month_should_roundtrip() {
1964        let value = IntervalYearMonthType::make_value(1, 2);
1965        assert_eq!(IntervalYearMonthType::to_months(value), 14);
1966    }
1967
1968    #[test]
1969    fn year_month_should_roundtrip_neg() {
1970        let value = IntervalYearMonthType::make_value(-1, -2);
1971        assert_eq!(IntervalYearMonthType::to_months(value), -14);
1972    }
1973
1974    fn test_layout<T: ArrowPrimitiveType>() {
1975        let layout = layout(&T::DATA_TYPE);
1976
1977        assert_eq!(layout.buffers.len(), 1);
1978
1979        let spec = &layout.buffers[0];
1980        assert_eq!(
1981            spec,
1982            &BufferSpec::FixedWidth {
1983                byte_width: std::mem::size_of::<T::Native>(),
1984                alignment: std::mem::align_of::<T::Native>(),
1985            }
1986        );
1987    }
1988
1989    #[test]
1990    fn test_layouts() {
1991        test_layout::<Int8Type>();
1992        test_layout::<Int16Type>();
1993        test_layout::<Int32Type>();
1994        test_layout::<Int64Type>();
1995        test_layout::<UInt8Type>();
1996        test_layout::<UInt16Type>();
1997        test_layout::<UInt32Type>();
1998        test_layout::<UInt64Type>();
1999        test_layout::<Float16Type>();
2000        test_layout::<Float32Type>();
2001        test_layout::<Float64Type>();
2002        test_layout::<Decimal32Type>();
2003        test_layout::<Decimal64Type>();
2004        test_layout::<Decimal128Type>();
2005        test_layout::<Decimal256Type>();
2006        test_layout::<TimestampNanosecondType>();
2007        test_layout::<TimestampMillisecondType>();
2008        test_layout::<TimestampMicrosecondType>();
2009        test_layout::<TimestampNanosecondType>();
2010        test_layout::<TimestampSecondType>();
2011        test_layout::<Date32Type>();
2012        test_layout::<Date64Type>();
2013        test_layout::<Time32SecondType>();
2014        test_layout::<Time32MillisecondType>();
2015        test_layout::<Time64MicrosecondType>();
2016        test_layout::<Time64NanosecondType>();
2017        test_layout::<IntervalMonthDayNanoType>();
2018        test_layout::<IntervalDayTimeType>();
2019        test_layout::<IntervalYearMonthType>();
2020        test_layout::<DurationNanosecondType>();
2021        test_layout::<DurationMicrosecondType>();
2022        test_layout::<DurationMillisecondType>();
2023        test_layout::<DurationSecondType>();
2024    }
2025
2026    #[test]
2027    fn timestamp_from_datetime() {
2028        use chrono::{FixedOffset, NaiveDate, NaiveTime, Utc};
2029
2030        // Test UTC timezone
2031        let date = NaiveDate::from_ymd_opt(2021, 1, 1).unwrap();
2032        let time = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
2033        let naive = NaiveDateTime::new(date, time);
2034        let datetime_utc = Utc.from_utc_datetime(&naive);
2035
2036        assert_eq!(
2037            TimestampSecondType::from_datetime(datetime_utc).unwrap(),
2038            1609502400
2039        );
2040        assert_eq!(
2041            TimestampMillisecondType::from_datetime(datetime_utc).unwrap(),
2042            1609502400000
2043        );
2044        assert_eq!(
2045            TimestampMicrosecondType::from_datetime(datetime_utc).unwrap(),
2046            1609502400000000
2047        );
2048        assert_eq!(
2049            TimestampNanosecondType::from_datetime(datetime_utc).unwrap(),
2050            1609502400000000000
2051        );
2052
2053        // Test FixedOffset timezone (+8:00): 12:00+8 = 04:00 UTC
2054        let tz_plus_8 = FixedOffset::east_opt(8 * 3600).unwrap();
2055        let datetime_plus_8 = tz_plus_8.from_local_datetime(&naive).unwrap();
2056        assert_eq!(
2057            TimestampSecondType::from_datetime(datetime_plus_8).unwrap(),
2058            1609502400 - 28800
2059        );
2060
2061        // Test subsecond precision
2062        let datetime = DateTime::from_timestamp(1000000000, 123456789).unwrap();
2063        assert_eq!(
2064            TimestampSecondType::from_datetime(datetime).unwrap(),
2065            1000000000
2066        );
2067        assert_eq!(
2068            TimestampMillisecondType::from_datetime(datetime).unwrap(),
2069            1000000000123
2070        );
2071        assert_eq!(
2072            TimestampMicrosecondType::from_datetime(datetime).unwrap(),
2073            1000000000123456
2074        );
2075        assert_eq!(
2076            TimestampNanosecondType::from_datetime(datetime).unwrap(),
2077            1000000000123456789
2078        );
2079    }
2080
2081    #[test]
2082    fn timestamp_from_datetime_overflow() {
2083        // Nanosecond precision has ~584 year range (1677-2262), easily overflows
2084        let far_past = DateTime::from_timestamp(-10_000_000_000, 0).unwrap();
2085        assert!(TimestampNanosecondType::from_datetime(far_past).is_none());
2086        // Other precisions should handle the same DateTime without overflow
2087        assert!(TimestampSecondType::from_datetime(far_past).is_some());
2088        assert!(TimestampMillisecondType::from_datetime(far_past).is_some());
2089        assert!(TimestampMicrosecondType::from_datetime(far_past).is_some());
2090
2091        let far_future = DateTime::from_timestamp(10_000_000_000, 0).unwrap();
2092        assert!(TimestampNanosecondType::from_datetime(far_future).is_none());
2093        assert!(TimestampSecondType::from_datetime(far_future).is_some());
2094        assert!(TimestampMillisecondType::from_datetime(far_future).is_some());
2095        assert!(TimestampMicrosecondType::from_datetime(far_future).is_some());
2096    }
2097
2098    #[test]
2099    fn timestamp_from_naive_datetime() {
2100        use crate::temporal_conversions::as_datetime_with_timezone;
2101        use chrono::{NaiveDate, NaiveTime};
2102
2103        let date = NaiveDate::from_ymd_opt(2021, 1, 1).unwrap();
2104        let time = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
2105        let naive = NaiveDateTime::new(date, time);
2106
2107        // Test UTC (tz=None)
2108        assert_eq!(
2109            TimestampSecondType::from_naive_datetime(naive, None).unwrap(),
2110            1609502400
2111        );
2112        assert_eq!(
2113            TimestampMillisecondType::from_naive_datetime(naive, None).unwrap(),
2114            1609502400000
2115        );
2116
2117        // Test with timezone (-05:00): 12:00-5 = 17:00 UTC
2118        let tz: Tz = "-05:00".parse().unwrap();
2119        let ts_sec = TimestampSecondType::from_naive_datetime(naive, Some(&tz)).unwrap();
2120        assert_eq!(ts_sec, 1609502400 + 5 * 3600);
2121
2122        // Test all types with timezone and roundtrip
2123        let date = NaiveDate::from_ymd_opt(2024, 6, 15).unwrap();
2124        let time = NaiveTime::from_hms_opt(14, 30, 45).unwrap();
2125        let naive = NaiveDateTime::new(date, time);
2126        let tz: Tz = "+01:00".parse().unwrap();
2127
2128        let ts_usec = TimestampMicrosecondType::from_naive_datetime(naive, Some(&tz)).unwrap();
2129        let recovered = as_datetime_with_timezone::<TimestampMicrosecondType>(ts_usec, tz).unwrap();
2130        assert_eq!(recovered.naive_local(), naive);
2131    }
2132
2133    #[test]
2134    #[cfg(feature = "chrono-tz")]
2135    fn timestamp_from_naive_datetime_ambiguous() {
2136        use chrono::{NaiveDate, NaiveTime};
2137
2138        // 2024-11-03 01:30:00 in US Eastern Time is ambiguous (daylight saving time ends)
2139        // It can be either 01:30:00 EDT (UTC-4) or 01:30:00 EST (UTC-5)
2140        let date = NaiveDate::from_ymd_opt(2024, 11, 3).unwrap();
2141        let time = NaiveTime::from_hms_opt(1, 30, 0).unwrap();
2142        let naive = NaiveDateTime::new(date, time);
2143        let tz: Tz = "America/New_York".parse().unwrap();
2144
2145        // Should return the first/earlier time (EDT, UTC-4) = 05:30:00 UTC
2146        let result = TimestampSecondType::from_naive_datetime(naive, Some(&tz));
2147        assert!(result.is_some());
2148        assert_eq!(result.unwrap(), 1730611800);
2149    }
2150
2151    #[test]
2152    #[cfg(feature = "chrono-tz")]
2153    fn timestamp_from_naive_datetime_none() {
2154        use chrono::{NaiveDate, NaiveTime};
2155
2156        // 2024-03-10 02:30:00 in US Eastern Time doesn't exist
2157        // (daylight saving time starts at 02:00, jumps to 03:00)
2158        let date = NaiveDate::from_ymd_opt(2024, 3, 10).unwrap();
2159        let time = NaiveTime::from_hms_opt(2, 30, 0).unwrap();
2160        let naive = NaiveDateTime::new(date, time);
2161        let tz: Tz = "America/New_York".parse().unwrap();
2162
2163        // Should return None
2164        let result = TimestampSecondType::from_naive_datetime(naive, Some(&tz));
2165        assert!(result.is_none());
2166
2167        // Test for all timestamp types
2168        assert!(TimestampMillisecondType::from_naive_datetime(naive, Some(&tz)).is_none());
2169        assert!(TimestampMicrosecondType::from_naive_datetime(naive, Some(&tz)).is_none());
2170        assert!(TimestampNanosecondType::from_naive_datetime(naive, Some(&tz)).is_none());
2171    }
2172}