arrow_buffer/
interval.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
18use crate::arith::derive_arith;
19use std::ops::Neg;
20
21/// Value of an IntervalMonthDayNano array
22///
23///  ## Representation
24///
25/// This type is stored as a single 128 bit integer, interpreted as three
26/// different signed integral fields:
27///
28/// 1. The number of months (32 bits)
29/// 2. The number days (32 bits)
30/// 2. The number of nanoseconds (64 bits).
31///
32/// Nanoseconds does not allow for leap seconds.
33///
34/// Each field is independent (e.g. there is no constraint that the quantity of
35/// nanoseconds represents less than a day's worth of time).
36///
37/// ```text
38/// ┌───────────────┬─────────────┬─────────────────────────────┐
39/// │     Months    │     Days    │            Nanos            │
40/// │   (32 bits)   │  (32 bits)  │          (64 bits)          │
41/// └───────────────┴─────────────┴─────────────────────────────┘
42/// 0            32             64                           128 bit offset
43/// ```
44/// Please see the [Arrow Spec](https://github.com/apache/arrow/blob/081b4022fe6f659d8765efc82b3f4787c5039e3c/format/Schema.fbs#L409-L415) for more details
45///
46///## Note on Comparing and Ordering for Calendar Types
47///
48/// Values of `IntervalMonthDayNano` are compared using their binary
49/// representation, which can lead to surprising results.
50///
51/// Spans of time measured in calendar units are not fixed in absolute size (e.g.
52/// number of seconds) which makes defining comparisons and ordering non trivial.
53/// For example `1 month` is 28 days for February but `1 month` is 31 days
54/// in December.
55///
56/// This makes the seemingly simple operation of comparing two intervals
57/// complicated in practice. For example is `1 month` more or less than `30
58/// days`? The answer depends on what month you are talking about.
59///
60/// This crate defines comparisons for calendar types using their binary
61/// representation which is fast and efficient, but leads
62/// to potentially surprising results.
63///
64/// For example a
65/// `IntervalMonthDayNano` of `1 month` will compare as **greater** than a
66/// `IntervalMonthDayNano` of `100 days` because the binary representation of `1 month`
67/// is larger than the binary representation of 100 days.
68#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
69#[repr(C)]
70pub struct IntervalMonthDayNano {
71    /// Number of months
72    pub months: i32,
73    /// Number of days
74    pub days: i32,
75    /// Number of nanoseconds
76    pub nanoseconds: i64,
77}
78
79impl IntervalMonthDayNano {
80    /// The additive identity i.e. `0`.
81    pub const ZERO: Self = Self::new(0, 0, 0);
82
83    /// The multiplicative identity, i.e. `1`.
84    pub const ONE: Self = Self::new(1, 1, 1);
85
86    /// The multiplicative inverse, i.e. `-1`.
87    pub const MINUS_ONE: Self = Self::new(-1, -1, -1);
88
89    /// The maximum value that can be represented
90    pub const MAX: Self = Self::new(i32::MAX, i32::MAX, i64::MAX);
91
92    /// The minimum value that can be represented
93    pub const MIN: Self = Self::new(i32::MIN, i32::MIN, i64::MIN);
94
95    /// Create a new [`IntervalMonthDayNano`]
96    #[inline]
97    pub const fn new(months: i32, days: i32, nanoseconds: i64) -> Self {
98        Self {
99            months,
100            days,
101            nanoseconds,
102        }
103    }
104
105    /// Computes the absolute value
106    #[inline]
107    pub fn wrapping_abs(self) -> Self {
108        Self {
109            months: self.months.wrapping_abs(),
110            days: self.days.wrapping_abs(),
111            nanoseconds: self.nanoseconds.wrapping_abs(),
112        }
113    }
114
115    /// Computes the absolute value
116    #[inline]
117    pub fn checked_abs(self) -> Option<Self> {
118        Some(Self {
119            months: self.months.checked_abs()?,
120            days: self.days.checked_abs()?,
121            nanoseconds: self.nanoseconds.checked_abs()?,
122        })
123    }
124
125    /// Negates the value
126    #[inline]
127    pub fn wrapping_neg(self) -> Self {
128        Self {
129            months: self.months.wrapping_neg(),
130            days: self.days.wrapping_neg(),
131            nanoseconds: self.nanoseconds.wrapping_neg(),
132        }
133    }
134
135    /// Negates the value
136    #[inline]
137    pub fn checked_neg(self) -> Option<Self> {
138        Some(Self {
139            months: self.months.checked_neg()?,
140            days: self.days.checked_neg()?,
141            nanoseconds: self.nanoseconds.checked_neg()?,
142        })
143    }
144
145    /// Performs wrapping addition
146    #[inline]
147    pub fn wrapping_add(self, other: Self) -> Self {
148        Self {
149            months: self.months.wrapping_add(other.months),
150            days: self.days.wrapping_add(other.days),
151            nanoseconds: self.nanoseconds.wrapping_add(other.nanoseconds),
152        }
153    }
154
155    /// Performs checked addition
156    #[inline]
157    pub fn checked_add(self, other: Self) -> Option<Self> {
158        Some(Self {
159            months: self.months.checked_add(other.months)?,
160            days: self.days.checked_add(other.days)?,
161            nanoseconds: self.nanoseconds.checked_add(other.nanoseconds)?,
162        })
163    }
164
165    /// Performs wrapping subtraction
166    #[inline]
167    pub fn wrapping_sub(self, other: Self) -> Self {
168        Self {
169            months: self.months.wrapping_sub(other.months),
170            days: self.days.wrapping_sub(other.days),
171            nanoseconds: self.nanoseconds.wrapping_sub(other.nanoseconds),
172        }
173    }
174
175    /// Performs checked subtraction
176    #[inline]
177    pub fn checked_sub(self, other: Self) -> Option<Self> {
178        Some(Self {
179            months: self.months.checked_sub(other.months)?,
180            days: self.days.checked_sub(other.days)?,
181            nanoseconds: self.nanoseconds.checked_sub(other.nanoseconds)?,
182        })
183    }
184
185    /// Performs wrapping multiplication
186    #[inline]
187    pub fn wrapping_mul(self, other: Self) -> Self {
188        Self {
189            months: self.months.wrapping_mul(other.months),
190            days: self.days.wrapping_mul(other.days),
191            nanoseconds: self.nanoseconds.wrapping_mul(other.nanoseconds),
192        }
193    }
194
195    /// Performs checked multiplication
196    pub fn checked_mul(self, other: Self) -> Option<Self> {
197        Some(Self {
198            months: self.months.checked_mul(other.months)?,
199            days: self.days.checked_mul(other.days)?,
200            nanoseconds: self.nanoseconds.checked_mul(other.nanoseconds)?,
201        })
202    }
203
204    /// Performs wrapping division
205    #[inline]
206    pub fn wrapping_div(self, other: Self) -> Self {
207        Self {
208            months: self.months.wrapping_div(other.months),
209            days: self.days.wrapping_div(other.days),
210            nanoseconds: self.nanoseconds.wrapping_div(other.nanoseconds),
211        }
212    }
213
214    /// Performs checked division
215    pub fn checked_div(self, other: Self) -> Option<Self> {
216        Some(Self {
217            months: self.months.checked_div(other.months)?,
218            days: self.days.checked_div(other.days)?,
219            nanoseconds: self.nanoseconds.checked_div(other.nanoseconds)?,
220        })
221    }
222
223    /// Performs wrapping remainder
224    #[inline]
225    pub fn wrapping_rem(self, other: Self) -> Self {
226        Self {
227            months: self.months.wrapping_rem(other.months),
228            days: self.days.wrapping_rem(other.days),
229            nanoseconds: self.nanoseconds.wrapping_rem(other.nanoseconds),
230        }
231    }
232
233    /// Performs checked remainder
234    pub fn checked_rem(self, other: Self) -> Option<Self> {
235        Some(Self {
236            months: self.months.checked_rem(other.months)?,
237            days: self.days.checked_rem(other.days)?,
238            nanoseconds: self.nanoseconds.checked_rem(other.nanoseconds)?,
239        })
240    }
241
242    /// Performs wrapping exponentiation
243    #[inline]
244    pub fn wrapping_pow(self, exp: u32) -> Self {
245        Self {
246            months: self.months.wrapping_pow(exp),
247            days: self.days.wrapping_pow(exp),
248            nanoseconds: self.nanoseconds.wrapping_pow(exp),
249        }
250    }
251
252    /// Performs checked exponentiation
253    #[inline]
254    pub fn checked_pow(self, exp: u32) -> Option<Self> {
255        Some(Self {
256            months: self.months.checked_pow(exp)?,
257            days: self.days.checked_pow(exp)?,
258            nanoseconds: self.nanoseconds.checked_pow(exp)?,
259        })
260    }
261}
262
263impl Neg for IntervalMonthDayNano {
264    type Output = Self;
265
266    #[cfg(debug_assertions)]
267    fn neg(self) -> Self::Output {
268        self.checked_neg().expect("IntervalMonthDayNano overflow")
269    }
270
271    #[cfg(not(debug_assertions))]
272    fn neg(self) -> Self::Output {
273        self.wrapping_neg()
274    }
275}
276
277derive_arith!(
278    IntervalMonthDayNano,
279    Add,
280    AddAssign,
281    add,
282    add_assign,
283    wrapping_add,
284    checked_add
285);
286derive_arith!(
287    IntervalMonthDayNano,
288    Sub,
289    SubAssign,
290    sub,
291    sub_assign,
292    wrapping_sub,
293    checked_sub
294);
295derive_arith!(
296    IntervalMonthDayNano,
297    Mul,
298    MulAssign,
299    mul,
300    mul_assign,
301    wrapping_mul,
302    checked_mul
303);
304derive_arith!(
305    IntervalMonthDayNano,
306    Div,
307    DivAssign,
308    div,
309    div_assign,
310    wrapping_div,
311    checked_div
312);
313derive_arith!(
314    IntervalMonthDayNano,
315    Rem,
316    RemAssign,
317    rem,
318    rem_assign,
319    wrapping_rem,
320    checked_rem
321);
322
323/// Value of an IntervalDayTime array
324///
325/// ## Representation
326///
327/// This type is stored as a single 64 bit integer, interpreted as two i32
328/// fields:
329///
330/// 1. the number of elapsed days
331/// 2. The number of milliseconds (no leap seconds),
332///
333/// ```text
334/// ┌──────────────┬──────────────┐
335/// │     Days     │ Milliseconds │
336/// │  (32 bits)   │  (32 bits)   │
337/// └──────────────┴──────────────┘
338/// 0              31            63 bit offset
339/// ```
340///
341/// Please see the [Arrow Spec](https://github.com/apache/arrow/blob/081b4022fe6f659d8765efc82b3f4787c5039e3c/format/Schema.fbs#L406-L408) for more details
342///
343/// ## Note on Comparing and Ordering for Calendar Types
344///
345/// Values of `IntervalDayTime` are compared using their binary representation,
346/// which can lead to surprising results. Please see the description of ordering on
347/// [`IntervalMonthDayNano`] for more details
348#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
349#[repr(C)]
350pub struct IntervalDayTime {
351    /// Number of days
352    pub days: i32,
353    /// Number of milliseconds
354    pub milliseconds: i32,
355}
356
357impl IntervalDayTime {
358    /// The additive identity i.e. `0`.
359    pub const ZERO: Self = Self::new(0, 0);
360
361    /// The multiplicative identity, i.e. `1`.
362    pub const ONE: Self = Self::new(1, 1);
363
364    /// The multiplicative inverse, i.e. `-1`.
365    pub const MINUS_ONE: Self = Self::new(-1, -1);
366
367    /// The maximum value that can be represented
368    pub const MAX: Self = Self::new(i32::MAX, i32::MAX);
369
370    /// The minimum value that can be represented
371    pub const MIN: Self = Self::new(i32::MIN, i32::MIN);
372
373    /// Create a new [`IntervalDayTime`]
374    #[inline]
375    pub const fn new(days: i32, milliseconds: i32) -> Self {
376        Self { days, milliseconds }
377    }
378
379    /// Computes the absolute value
380    #[inline]
381    pub fn wrapping_abs(self) -> Self {
382        Self {
383            days: self.days.wrapping_abs(),
384            milliseconds: self.milliseconds.wrapping_abs(),
385        }
386    }
387
388    /// Computes the absolute value
389    #[inline]
390    pub fn checked_abs(self) -> Option<Self> {
391        Some(Self {
392            days: self.days.checked_abs()?,
393            milliseconds: self.milliseconds.checked_abs()?,
394        })
395    }
396
397    /// Negates the value
398    #[inline]
399    pub fn wrapping_neg(self) -> Self {
400        Self {
401            days: self.days.wrapping_neg(),
402            milliseconds: self.milliseconds.wrapping_neg(),
403        }
404    }
405
406    /// Negates the value
407    #[inline]
408    pub fn checked_neg(self) -> Option<Self> {
409        Some(Self {
410            days: self.days.checked_neg()?,
411            milliseconds: self.milliseconds.checked_neg()?,
412        })
413    }
414
415    /// Performs wrapping addition
416    #[inline]
417    pub fn wrapping_add(self, other: Self) -> Self {
418        Self {
419            days: self.days.wrapping_add(other.days),
420            milliseconds: self.milliseconds.wrapping_add(other.milliseconds),
421        }
422    }
423
424    /// Performs checked addition
425    #[inline]
426    pub fn checked_add(self, other: Self) -> Option<Self> {
427        Some(Self {
428            days: self.days.checked_add(other.days)?,
429            milliseconds: self.milliseconds.checked_add(other.milliseconds)?,
430        })
431    }
432
433    /// Performs wrapping subtraction
434    #[inline]
435    pub fn wrapping_sub(self, other: Self) -> Self {
436        Self {
437            days: self.days.wrapping_sub(other.days),
438            milliseconds: self.milliseconds.wrapping_sub(other.milliseconds),
439        }
440    }
441
442    /// Performs checked subtraction
443    #[inline]
444    pub fn checked_sub(self, other: Self) -> Option<Self> {
445        Some(Self {
446            days: self.days.checked_sub(other.days)?,
447            milliseconds: self.milliseconds.checked_sub(other.milliseconds)?,
448        })
449    }
450
451    /// Performs wrapping multiplication
452    #[inline]
453    pub fn wrapping_mul(self, other: Self) -> Self {
454        Self {
455            days: self.days.wrapping_mul(other.days),
456            milliseconds: self.milliseconds.wrapping_mul(other.milliseconds),
457        }
458    }
459
460    /// Performs checked multiplication
461    pub fn checked_mul(self, other: Self) -> Option<Self> {
462        Some(Self {
463            days: self.days.checked_mul(other.days)?,
464            milliseconds: self.milliseconds.checked_mul(other.milliseconds)?,
465        })
466    }
467
468    /// Performs wrapping division
469    #[inline]
470    pub fn wrapping_div(self, other: Self) -> Self {
471        Self {
472            days: self.days.wrapping_div(other.days),
473            milliseconds: self.milliseconds.wrapping_div(other.milliseconds),
474        }
475    }
476
477    /// Performs checked division
478    pub fn checked_div(self, other: Self) -> Option<Self> {
479        Some(Self {
480            days: self.days.checked_div(other.days)?,
481            milliseconds: self.milliseconds.checked_div(other.milliseconds)?,
482        })
483    }
484
485    /// Performs wrapping remainder
486    #[inline]
487    pub fn wrapping_rem(self, other: Self) -> Self {
488        Self {
489            days: self.days.wrapping_rem(other.days),
490            milliseconds: self.milliseconds.wrapping_rem(other.milliseconds),
491        }
492    }
493
494    /// Performs checked remainder
495    pub fn checked_rem(self, other: Self) -> Option<Self> {
496        Some(Self {
497            days: self.days.checked_rem(other.days)?,
498            milliseconds: self.milliseconds.checked_rem(other.milliseconds)?,
499        })
500    }
501
502    /// Performs wrapping exponentiation
503    #[inline]
504    pub fn wrapping_pow(self, exp: u32) -> Self {
505        Self {
506            days: self.days.wrapping_pow(exp),
507            milliseconds: self.milliseconds.wrapping_pow(exp),
508        }
509    }
510
511    /// Performs checked exponentiation
512    #[inline]
513    pub fn checked_pow(self, exp: u32) -> Option<Self> {
514        Some(Self {
515            days: self.days.checked_pow(exp)?,
516            milliseconds: self.milliseconds.checked_pow(exp)?,
517        })
518    }
519}
520
521impl Neg for IntervalDayTime {
522    type Output = Self;
523
524    #[cfg(debug_assertions)]
525    fn neg(self) -> Self::Output {
526        self.checked_neg().expect("IntervalDayMillisecond overflow")
527    }
528
529    #[cfg(not(debug_assertions))]
530    fn neg(self) -> Self::Output {
531        self.wrapping_neg()
532    }
533}
534
535derive_arith!(
536    IntervalDayTime,
537    Add,
538    AddAssign,
539    add,
540    add_assign,
541    wrapping_add,
542    checked_add
543);
544derive_arith!(
545    IntervalDayTime,
546    Sub,
547    SubAssign,
548    sub,
549    sub_assign,
550    wrapping_sub,
551    checked_sub
552);
553derive_arith!(
554    IntervalDayTime,
555    Mul,
556    MulAssign,
557    mul,
558    mul_assign,
559    wrapping_mul,
560    checked_mul
561);
562derive_arith!(
563    IntervalDayTime,
564    Div,
565    DivAssign,
566    div,
567    div_assign,
568    wrapping_div,
569    checked_div
570);
571derive_arith!(
572    IntervalDayTime,
573    Rem,
574    RemAssign,
575    rem,
576    rem_assign,
577    wrapping_rem,
578    checked_rem
579);