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