Skip to main content

risingwave_common/types/
interval.rs

1// Copyright 2022 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::cmp::Ordering;
16use std::error::Error;
17use std::fmt::{Display, Formatter};
18use std::hash::{Hash, Hasher};
19use std::io::{Cursor, Write};
20use std::ops::{Add, Neg, Sub};
21use std::sync::LazyLock;
22
23use anyhow::Context;
24use byteorder::{BigEndian, NetworkEndian, ReadBytesExt, WriteBytesExt};
25use bytes::BytesMut;
26use num_traits::{CheckedAdd, CheckedNeg, CheckedSub, Zero};
27use postgres_types::to_sql_checked;
28use regex::Regex;
29use risingwave_pb::data::PbInterval;
30use rust_decimal::prelude::Decimal;
31
32use super::*;
33
34/// Every interval can be represented by a `Interval`.
35///
36/// Note that the difference between Interval and Instant.
37/// For example, `5 yrs 1 month 25 days 23:22:57` is a interval (Can be interpreted by Interval Unit
38/// with months = 61, days = 25, usecs = (57 + 23 * 3600 + 22 * 60) * 1000000),
39/// `1970-01-01 04:05:06` is a Instant or Timestamp
40/// One month may contain 28/31 days. One day may contain 23/25 hours.
41/// This internals is learned from PG:
42/// <https://www.postgresql.org/docs/9.1/datatype-datetime.html#:~:text=field%20is%20negative.-,Internally,-interval%20values%20are>
43#[derive(Debug, Clone, Copy, Default)]
44pub struct Interval {
45    months: i32,
46    days: i32,
47    usecs: i64,
48}
49
50impl ZeroHeapSize for Interval {}
51
52const USECS_PER_SEC: i64 = 1_000_000;
53const USECS_PER_DAY: i64 = 86400 * USECS_PER_SEC;
54const USECS_PER_MONTH: i64 = 30 * USECS_PER_DAY;
55
56impl Interval {
57    /// Smallest interval value.
58    pub const MIN: Self = Self {
59        months: i32::MIN,
60        days: i32::MIN,
61        usecs: i64::MIN,
62    };
63    pub const USECS_PER_DAY: i64 = USECS_PER_DAY;
64    pub const USECS_PER_MONTH: i64 = USECS_PER_MONTH;
65    pub const USECS_PER_SEC: i64 = USECS_PER_SEC;
66
67    /// Creates a new `Interval` from the given number of months, days, and microseconds.
68    pub fn from_month_day_usec(months: i32, days: i32, usecs: i64) -> Self {
69        Interval {
70            months,
71            days,
72            usecs,
73        }
74    }
75
76    /// Returns the total number of whole months.
77    ///
78    /// Note the difference between `months` and `months_field`.
79    ///
80    /// We have: `months = years_field * 12 + months_field`
81    ///
82    /// # Example
83    /// ```
84    /// # use risingwave_common::types::Interval;
85    /// let interval: Interval = "5 yrs 1 month".parse().unwrap();
86    /// assert_eq!(interval.months(), 61);
87    /// assert_eq!(interval.months_field(), 1);
88    /// ```
89    pub fn months(&self) -> i32 {
90        self.months
91    }
92
93    /// Returns the number of days.
94    pub fn days(&self) -> i32 {
95        self.days
96    }
97
98    /// Returns the number of microseconds.
99    ///
100    /// Note the difference between `usecs` and `seconds_in_micros`.
101    ///
102    /// We have: `usecs = (hours_field * 3600 + minutes_field * 60) * 1_000_000 +
103    /// seconds_in_micros`.
104    pub fn usecs(&self) -> i64 {
105        self.usecs
106    }
107
108    /// Calculates the remaining number of microseconds.
109    /// range: `0..86_400_000_000`
110    ///
111    /// Note the difference between `usecs` and `usecs_of_day`.
112    /// ```
113    /// # use risingwave_common::types::Interval;
114    /// let interval: Interval = "-1:00:00".parse().unwrap();
115    /// assert_eq!(interval.usecs(), -1 * 60 * 60 * 1_000_000);
116    /// assert_eq!(interval.usecs_of_day(), 23 * 60 * 60 * 1_000_000);
117    /// ```
118    pub fn usecs_of_day(&self) -> u64 {
119        self.usecs.rem_euclid(USECS_PER_DAY) as u64
120    }
121
122    /// Returns the years field. range: unlimited
123    ///
124    /// # Example
125    /// ```
126    /// # use risingwave_common::types::Interval;
127    /// let interval: Interval = "2332 yrs 12 months".parse().unwrap();
128    /// assert_eq!(interval.years_field(), 2333);
129    /// ```
130    pub fn years_field(&self) -> i32 {
131        self.months / 12
132    }
133
134    /// Returns the months field. range: `-11..=11`
135    ///
136    /// # Example
137    /// ```
138    /// # use risingwave_common::types::Interval;
139    /// let interval: Interval = "15 months".parse().unwrap();
140    /// assert_eq!(interval.months_field(), 3);
141    ///
142    /// let interval: Interval = "-15 months".parse().unwrap();
143    /// assert_eq!(interval.months_field(), -3);
144    /// ```
145    pub fn months_field(&self) -> i32 {
146        self.months % 12
147    }
148
149    /// Returns the days field. range: unlimited
150    ///
151    /// # Example
152    /// ```
153    /// # use risingwave_common::types::Interval;
154    /// let interval: Interval = "1 months 100 days 25:00:00".parse().unwrap();
155    /// assert_eq!(interval.days_field(), 100);
156    /// ```
157    pub fn days_field(&self) -> i32 {
158        self.days
159    }
160
161    /// Returns the hours field. range: unlimited
162    ///
163    /// # Example
164    /// ```
165    /// # use risingwave_common::types::Interval;
166    /// let interval: Interval = "25:00:00".parse().unwrap();
167    /// assert_eq!(interval.hours_field(), 25);
168    ///
169    /// let interval: Interval = "-25:00:00".parse().unwrap();
170    /// assert_eq!(interval.hours_field(), -25);
171    /// ```
172    pub fn hours_field(&self) -> i64 {
173        self.usecs / USECS_PER_SEC / 3600
174    }
175
176    /// Returns the minutes field. range: `-59..=-59`
177    ///
178    /// # Example
179    /// ```
180    /// # use risingwave_common::types::Interval;
181    /// let interval: Interval = "00:20:00".parse().unwrap();
182    /// assert_eq!(interval.minutes_field(), 20);
183    ///
184    /// let interval: Interval = "-00:20:00".parse().unwrap();
185    /// assert_eq!(interval.minutes_field(), -20);
186    /// ```
187    pub fn minutes_field(&self) -> i32 {
188        (self.usecs / USECS_PER_SEC / 60 % 60) as i32
189    }
190
191    /// Returns the seconds field, including fractional parts, in microseconds.
192    /// range: `-59_999_999..=59_999_999`
193    ///
194    /// # Example
195    /// ```
196    /// # use risingwave_common::types::Interval;
197    /// let interval: Interval = "01:02:03.45678".parse().unwrap();
198    /// assert_eq!(interval.seconds_in_micros(), 3_456_780);
199    ///
200    /// let interval: Interval = "-01:02:03.45678".parse().unwrap();
201    /// assert_eq!(interval.seconds_in_micros(), -3_456_780);
202    /// ```
203    pub fn seconds_in_micros(&self) -> i32 {
204        (self.usecs % (USECS_PER_SEC * 60)) as i32
205    }
206
207    /// Returns the total number of microseconds, as defined by PostgreSQL `extract`.
208    ///
209    /// Note this value is not used by interval ordering (`IntervalCmpValue`) and is not consistent
210    /// with it.
211    pub fn epoch_in_micros(&self) -> i128 {
212        // https://github.com/postgres/postgres/blob/REL_15_2/src/backend/utils/adt/timestamp.c#L5304
213
214        const DAYS_PER_YEAR_X4: i32 = 365 * 4 + 1;
215        const DAYS_PER_MONTH: i32 = 30;
216        const SECS_PER_DAY: i32 = 86400;
217        const MONTHS_PER_YEAR: i32 = 12;
218
219        // To do this calculation in integer arithmetic even though
220        // DAYS_PER_YEAR is fractional, multiply everything by 4 and then
221        // divide by 4 again at the end.  This relies on DAYS_PER_YEAR
222        // being a multiple of 0.25 and on SECS_PER_DAY being a multiple
223        // of 4.
224        let secs_from_day_month = ((DAYS_PER_YEAR_X4 as i64)
225            * (self.months / MONTHS_PER_YEAR) as i64
226            + (4 * DAYS_PER_MONTH as i64) * (self.months % MONTHS_PER_YEAR) as i64
227            + 4 * self.days as i64)
228            * (SECS_PER_DAY / 4) as i64;
229
230        secs_from_day_month as i128 * USECS_PER_SEC as i128 + self.usecs as i128
231    }
232
233    pub fn from_protobuf(cursor: &mut Cursor<&[u8]>) -> ArrayResult<Interval> {
234        let mut read = || {
235            let months = cursor.read_i32::<BigEndian>()?;
236            let days = cursor.read_i32::<BigEndian>()?;
237            let usecs = cursor.read_i64::<BigEndian>()?;
238
239            Ok::<_, std::io::Error>(Interval::from_month_day_usec(months, days, usecs))
240        };
241
242        Ok(read().context("failed to read Interval from buffer")?)
243    }
244
245    pub fn to_protobuf<T: Write>(self, output: &mut T) -> ArrayResult<usize> {
246        output.write_i32::<BigEndian>(self.months)?;
247        output.write_i32::<BigEndian>(self.days)?;
248        output.write_i64::<BigEndian>(self.usecs)?;
249        Ok(16)
250    }
251
252    /// Multiple [`Interval`] by an integer with overflow check.
253    pub fn checked_mul_int<I>(&self, rhs: I) -> Option<Self>
254    where
255        I: TryInto<i32>,
256    {
257        let rhs = rhs.try_into().ok()?;
258        let months = self.months.checked_mul(rhs)?;
259        let days = self.days.checked_mul(rhs)?;
260        let usecs = self.usecs.checked_mul(rhs as i64)?;
261
262        Some(Interval {
263            months,
264            days,
265            usecs,
266        })
267    }
268
269    /// Internal utility used by [`Self::mul_float`] and [`Self::div_float`] to adjust fractional
270    /// units. Not intended as general constructor.
271    fn from_floats(months: f64, days: f64, usecs: f64) -> Option<Self> {
272        // TSROUND in include/datatype/timestamp.h
273        // round eagerly at usecs precision because floats are imprecise
274        let months_round_usecs = |months: f64| {
275            (months * (USECS_PER_MONTH as f64)).round_ties_even() / (USECS_PER_MONTH as f64)
276        };
277
278        let days_round_usecs =
279            |days: f64| (days * (USECS_PER_DAY as f64)).round_ties_even() / (USECS_PER_DAY as f64);
280
281        let trunc_fract = |num: f64| (num.trunc(), num.fract());
282
283        // Handle months
284        let (months, months_fract) = trunc_fract(months_round_usecs(months));
285        if months.is_nan() || months < i32::MIN.into() || months > i32::MAX.into() {
286            return None;
287        }
288        let months = months as i32;
289        let (leftover_days, leftover_days_fract) =
290            trunc_fract(days_round_usecs(months_fract * 30.));
291
292        // Handle days
293        let (days, days_fract) = trunc_fract(days_round_usecs(days));
294        if days.is_nan() || days < i32::MIN.into() || days > i32::MAX.into() {
295            return None;
296        }
297        // Note that PostgreSQL split the integer part and fractional part individually before
298        // adding `leftover_days`. This makes a difference for mixed sign interval.
299        // For example in `interval '3 mons -3 days' / 2`
300        // * `leftover_days` is `15`
301        // * `days` from input is `-1.5`
302        // If we add first, we get `13.5` which is `13 days 12:00:00`;
303        // If we split first, we get `14` and `-0.5`, which ends up as `14 days -12:00:00`.
304        let (days_fract_whole, days_fract) =
305            trunc_fract(days_round_usecs(days_fract + leftover_days_fract));
306        let days = (days as i32)
307            .checked_add(leftover_days as i32)?
308            .checked_add(days_fract_whole as i32)?;
309        let leftover_usecs = days_fract * (USECS_PER_DAY as f64);
310
311        // Handle usecs
312        let result_usecs = usecs + leftover_usecs;
313        let usecs = result_usecs.round_ties_even();
314        if usecs.is_nan() || usecs < (i64::MIN as f64) || usecs > (i64::MAX as f64) {
315            return None;
316        }
317        let usecs = usecs as i64;
318
319        Some(Self {
320            months,
321            days,
322            usecs,
323        })
324    }
325
326    /// Divides [`Interval`] by an integer/float with zero check.
327    pub fn div_float<I>(&self, rhs: I) -> Option<Self>
328    where
329        I: TryInto<F64>,
330    {
331        let rhs = rhs.try_into().ok()?;
332        let rhs = rhs.0;
333
334        if rhs == 0.0 {
335            return None;
336        }
337
338        Self::from_floats(
339            self.months as f64 / rhs,
340            self.days as f64 / rhs,
341            self.usecs as f64 / rhs,
342        )
343    }
344
345    /// times [`Interval`] with an integer/float.
346    pub fn mul_float<I>(&self, rhs: I) -> Option<Self>
347    where
348        I: TryInto<F64>,
349    {
350        let rhs = rhs.try_into().ok()?;
351        let rhs = rhs.0;
352
353        Self::from_floats(
354            self.months as f64 * rhs,
355            self.days as f64 * rhs,
356            self.usecs as f64 * rhs,
357        )
358    }
359
360    /// Performs an exact division, returns [`None`] if for any unit, lhs % rhs != 0.
361    pub fn exact_div(&self, rhs: &Self) -> Option<i64> {
362        let mut res = None;
363        let mut check_unit = |l: i64, r: i64| {
364            if l == 0 && r == 0 {
365                return Some(());
366            }
367            if l != 0 && r == 0 {
368                return None;
369            }
370            if l % r != 0 {
371                return None;
372            }
373            let new_res = l / r;
374            if let Some(old_res) = res {
375                if old_res != new_res {
376                    return None;
377                }
378            } else {
379                res = Some(new_res);
380            }
381
382            Some(())
383        };
384
385        check_unit(self.months as i64, rhs.months as i64)?;
386        check_unit(self.days as i64, rhs.days as i64)?;
387        check_unit(self.usecs, rhs.usecs)?;
388
389        res
390    }
391
392    /// Checks if [`Interval`] is positive.
393    pub fn is_positive(&self) -> bool {
394        self > &Self::from_month_day_usec(0, 0, 0)
395    }
396
397    /// Checks if all fields of [`Interval`] are all non-negative.
398    pub fn is_never_negative(&self) -> bool {
399        self.months >= 0 && self.days >= 0 && self.usecs >= 0
400    }
401
402    /// Truncate the interval to the precision of milliseconds.
403    ///
404    /// # Example
405    /// ```
406    /// # use risingwave_common::types::Interval;
407    /// let interval: Interval = "5 years 1 mon 25 days 23:22:57.123".parse().unwrap();
408    /// assert_eq!(
409    ///     interval.truncate_millis().to_string(),
410    ///     "5 years 1 mon 25 days 23:22:57.123"
411    /// );
412    /// ```
413    pub const fn truncate_millis(self) -> Self {
414        Interval {
415            months: self.months,
416            days: self.days,
417            usecs: self.usecs / 1000 * 1000,
418        }
419    }
420
421    /// Truncate the interval to the precision of seconds.
422    ///
423    /// # Example
424    /// ```
425    /// # use risingwave_common::types::Interval;
426    /// let interval: Interval = "5 years 1 mon 25 days 23:22:57.123".parse().unwrap();
427    /// assert_eq!(
428    ///     interval.truncate_second().to_string(),
429    ///     "5 years 1 mon 25 days 23:22:57"
430    /// );
431    /// ```
432    pub const fn truncate_second(self) -> Self {
433        Interval {
434            months: self.months,
435            days: self.days,
436            usecs: self.usecs / USECS_PER_SEC * USECS_PER_SEC,
437        }
438    }
439
440    /// Truncate the interval to the precision of minutes.
441    ///
442    /// # Example
443    /// ```
444    /// # use risingwave_common::types::Interval;
445    /// let interval: Interval = "5 years 1 mon 25 days 23:22:57.123".parse().unwrap();
446    /// assert_eq!(
447    ///     interval.truncate_minute().to_string(),
448    ///     "5 years 1 mon 25 days 23:22:00"
449    /// );
450    /// ```
451    pub const fn truncate_minute(self) -> Self {
452        Interval {
453            months: self.months,
454            days: self.days,
455            usecs: self.usecs / USECS_PER_SEC / 60 * USECS_PER_SEC * 60,
456        }
457    }
458
459    /// Truncate the interval to the precision of hours.
460    ///
461    /// # Example
462    /// ```
463    /// # use risingwave_common::types::Interval;
464    /// let interval: Interval = "5 years 1 mon 25 days 23:22:57.123".parse().unwrap();
465    /// assert_eq!(
466    ///     interval.truncate_hour().to_string(),
467    ///     "5 years 1 mon 25 days 23:00:00"
468    /// );
469    /// ```
470    pub const fn truncate_hour(self) -> Self {
471        Interval {
472            months: self.months,
473            days: self.days,
474            usecs: self.usecs / USECS_PER_SEC / 60 / 60 * USECS_PER_SEC * 60 * 60,
475        }
476    }
477
478    /// Truncate the interval to the precision of days.
479    ///
480    /// # Example
481    /// ```
482    /// # use risingwave_common::types::Interval;
483    /// let interval: Interval = "5 years 1 mon 25 days 23:22:57.123".parse().unwrap();
484    /// assert_eq!(interval.truncate_day().to_string(), "5 years 1 mon 25 days");
485    /// ```
486    pub const fn truncate_day(self) -> Self {
487        Interval {
488            months: self.months,
489            days: self.days,
490            usecs: 0,
491        }
492    }
493
494    /// Truncate the interval to the precision of months.
495    ///
496    /// # Example
497    /// ```
498    /// # use risingwave_common::types::Interval;
499    /// let interval: Interval = "5 years 1 mon 25 days 23:22:57.123".parse().unwrap();
500    /// assert_eq!(interval.truncate_month().to_string(), "5 years 1 mon");
501    /// ```
502    pub const fn truncate_month(self) -> Self {
503        Interval {
504            months: self.months,
505            days: 0,
506            usecs: 0,
507        }
508    }
509
510    /// Truncate the interval to the precision of quarters.
511    ///
512    /// # Example
513    /// ```
514    /// # use risingwave_common::types::Interval;
515    /// let interval: Interval = "5 years 1 mon 25 days 23:22:57.123".parse().unwrap();
516    /// assert_eq!(interval.truncate_quarter().to_string(), "5 years");
517    /// ```
518    pub const fn truncate_quarter(self) -> Self {
519        Interval {
520            months: self.months / 3 * 3,
521            days: 0,
522            usecs: 0,
523        }
524    }
525
526    /// Truncate the interval to the precision of years.
527    ///
528    /// # Example
529    /// ```
530    /// # use risingwave_common::types::Interval;
531    /// let interval: Interval = "5 years 1 mon 25 days 23:22:57.123".parse().unwrap();
532    /// assert_eq!(interval.truncate_year().to_string(), "5 years");
533    /// ```
534    pub const fn truncate_year(self) -> Self {
535        Interval {
536            months: self.months / 12 * 12,
537            days: 0,
538            usecs: 0,
539        }
540    }
541
542    /// Truncate the interval to the precision of decades.
543    ///
544    /// # Example
545    /// ```
546    /// # use risingwave_common::types::Interval;
547    /// let interval: Interval = "15 years 1 mon 25 days 23:22:57.123".parse().unwrap();
548    /// assert_eq!(interval.truncate_decade().to_string(), "10 years");
549    /// ```
550    pub const fn truncate_decade(self) -> Self {
551        Interval {
552            months: self.months / 12 / 10 * 12 * 10,
553            days: 0,
554            usecs: 0,
555        }
556    }
557
558    /// Truncate the interval to the precision of centuries.
559    ///
560    /// # Example
561    /// ```
562    /// # use risingwave_common::types::Interval;
563    /// let interval: Interval = "115 years 1 mon 25 days 23:22:57.123".parse().unwrap();
564    /// assert_eq!(interval.truncate_century().to_string(), "100 years");
565    /// ```
566    pub const fn truncate_century(self) -> Self {
567        Interval {
568            months: self.months / 12 / 100 * 12 * 100,
569            days: 0,
570            usecs: 0,
571        }
572    }
573
574    /// Truncate the interval to the precision of millenniums.
575    ///
576    /// # Example
577    /// ```
578    /// # use risingwave_common::types::Interval;
579    /// let interval: Interval = "1115 years 1 mon 25 days 23:22:57.123".parse().unwrap();
580    /// assert_eq!(interval.truncate_millennium().to_string(), "1000 years");
581    /// ```
582    pub const fn truncate_millennium(self) -> Self {
583        Interval {
584            months: self.months / 12 / 1000 * 12 * 1000,
585            days: 0,
586            usecs: 0,
587        }
588    }
589
590    // Assuming 1 day = 24 hours, adjust `abs(usecs)` to be less than 24 hours, and has the same
591    // sign with `days`.
592    pub fn justify_hour(self) -> Option<Self> {
593        let whole_day = (self.usecs / USECS_PER_DAY) as i32;
594        let mut usecs = self.usecs % USECS_PER_DAY;
595        let mut days = self.days.checked_add(whole_day)?;
596        if days > 0 && usecs < 0 {
597            usecs += USECS_PER_DAY;
598            days -= 1;
599        } else if days < 0 && usecs > 0 {
600            usecs -= USECS_PER_DAY;
601            days += 1;
602        }
603        Some(Self::from_month_day_usec(self.months, days, usecs))
604    }
605}
606
607/// A separate mod so that `use types::*` or `use interval::*` does not `use IntervalTestExt` by
608/// accident.
609pub mod test_utils {
610    use super::*;
611
612    /// These constructors may panic when value out of bound. Only use in tests with known input.
613    pub trait IntervalTestExt {
614        fn from_ymd(year: i32, month: i32, days: i32) -> Self;
615        fn from_month(months: i32) -> Self;
616        fn from_days(days: i32) -> Self;
617        fn from_millis(ms: i64) -> Self;
618        fn from_minutes(minutes: i64) -> Self;
619    }
620
621    impl IntervalTestExt for Interval {
622        fn from_ymd(year: i32, month: i32, days: i32) -> Self {
623            let months = year * 12 + month;
624            let usecs = 0;
625            Interval {
626                months,
627                days,
628                usecs,
629            }
630        }
631
632        fn from_month(months: i32) -> Self {
633            Interval {
634                months,
635                ..Default::default()
636            }
637        }
638
639        fn from_days(days: i32) -> Self {
640            Self {
641                days,
642                ..Default::default()
643            }
644        }
645
646        fn from_millis(ms: i64) -> Self {
647            Self {
648                usecs: ms * 1000,
649                ..Default::default()
650            }
651        }
652
653        fn from_minutes(minutes: i64) -> Self {
654            Self {
655                usecs: USECS_PER_SEC * 60 * minutes,
656                ..Default::default()
657            }
658        }
659    }
660}
661
662/// Wrapper so that `Debug for IntervalDisplay` would use the concise format of `Display for
663/// Interval`.
664#[derive(Clone, Copy)]
665pub struct IntervalDisplay<'a> {
666    pub core: &'a Interval,
667}
668
669impl std::fmt::Display for IntervalDisplay<'_> {
670    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
671        (self as &dyn std::fmt::Debug).fmt(f)
672    }
673}
674
675impl std::fmt::Debug for IntervalDisplay<'_> {
676    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
677        write!(f, "{}", self.core)
678    }
679}
680
681/// <https://github.com/postgres/postgres/blob/REL_15_2/src/backend/utils/adt/timestamp.c#L2384>
682///
683/// Do NOT make this `pub` as the assumption of 1 month = 30 days and 1 day = 24 hours does not
684/// always hold in other places.
685///
686/// Given this equality definition in PostgreSQL, different interval values can be considered equal,
687/// forming equivalence classes. For example:
688/// * '-45 days' == '-1 months -15 days' == '1 months -75 days'
689/// * '-2147483646 months -210 days' == '-2147483648 months -150 days' == '-2075900865 months
690///   -2147483640 days'
691///
692/// To hash and memcompare them, we need to pick a representative for each equivalence class, and
693/// then map all values from the same equivalence class to the same representative. There are 3
694/// choices (may be more):
695/// (a) an `i128` of total `usecs`, with `months` and `days` transformed into `usecs`;
696/// (b) the justified interval, as defined by PostgreSQL `justify_interval`;
697/// (c) the alternate representative interval that maximizes `abs` of smaller units;
698///
699/// For simplicity we will assume there are only `months` and `days` and ignore `usecs` below.
700///
701/// The justified interval is more human friendly. It requires all units to have the same sign, and
702/// that `0 <= abs(usecs) < USECS_PER_DAY && 0 <= abs(days) < 30`. However, it may overflow. In the
703/// 2 examples above, '-1 months -15 days' is the justified interval of the first equivalence class,
704/// but there is no justified interval in the second one. It would be '-2147483653 months' but this
705/// overflows `i32`. A lot of bits are wasted in a justified interval because `days` is using
706/// `i32` for `-29..=29` only.
707///
708/// The alternate representative interval aims to avoid this overflow. It still requires all units
709/// to have the same sign, but maximizes `abs` of smaller unit rather than limit it to `29`. The
710/// alternate representative of the 2 examples above are '-45 days' and '-2075900865 months
711/// -2147483640 days'. The alternate representative interval always exists.
712///
713/// For serialize, we could use any of 3, with a workaround of using (i33, i6, i38) rather than
714/// (i32, i32, i64) to avoid overflow of the justified interval. We chose the `usecs: i128` option.
715///
716/// For deserialize, we attempt justified interval first and fallback to alternate. This could give
717/// human friendly results in common cases and still guarantee no overflow, as long as the bytes
718/// were serialized properly.
719///
720/// Note the alternate representative interval does not exist in PostgreSQL as they do not
721/// deserialize from `IntervalCmpValue`.
722#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
723struct IntervalCmpValue(i128);
724
725impl From<Interval> for IntervalCmpValue {
726    fn from(value: Interval) -> Self {
727        let days = (value.days as i64) + 30i64 * (value.months as i64);
728        let usecs = (value.usecs as i128) + (USECS_PER_DAY as i128) * (days as i128);
729        Self(usecs)
730    }
731}
732
733impl Ord for Interval {
734    fn cmp(&self, other: &Self) -> Ordering {
735        IntervalCmpValue::from(*self).cmp(&(*other).into())
736    }
737}
738
739impl PartialOrd for Interval {
740    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
741        Some(self.cmp(other))
742    }
743}
744
745impl PartialEq for Interval {
746    fn eq(&self, other: &Self) -> bool {
747        self.cmp(other).is_eq()
748    }
749}
750
751impl Eq for Interval {}
752
753impl Hash for Interval {
754    fn hash<H: Hasher>(&self, state: &mut H) {
755        IntervalCmpValue::from(*self).hash(state);
756    }
757}
758
759/// Loss of information during the process due to `IntervalCmpValue`. Only intended for
760/// memcomparable encoding.
761impl Serialize for Interval {
762    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
763    where
764        S: serde::Serializer,
765    {
766        let cmp_value = IntervalCmpValue::from(*self);
767        cmp_value.0.serialize(serializer)
768    }
769}
770
771impl IntervalCmpValue {
772    /// Recover the justified interval from this equivalence class, if it exists.
773    fn as_justified(&self) -> Option<Interval> {
774        let usecs = (self.0 % (USECS_PER_DAY as i128)) as i64;
775        let remaining_days = self.0 / (USECS_PER_DAY as i128);
776        let days = (remaining_days % 30) as i32;
777        let months = (remaining_days / 30).try_into().ok()?;
778        Some(Interval::from_month_day_usec(months, days, usecs))
779    }
780
781    /// Recover the alternate representative interval from this equivalence class.
782    /// It always exists unless the encoding is invalid. See [`IntervalCmpValue`] for details.
783    fn as_alternate(&self) -> Option<Interval> {
784        match self.0.cmp(&0) {
785            Ordering::Equal => Some(Interval::from_month_day_usec(0, 0, 0)),
786            Ordering::Greater => {
787                let remaining_usecs = self.0;
788                let mut usecs = (remaining_usecs % (USECS_PER_DAY as i128)) as i64;
789                let mut remaining_days = remaining_usecs / (USECS_PER_DAY as i128);
790                // `usecs` is now smaller than `USECS_PER_DAY` but has 64 bits.
791                // How much more days (multiples of `USECS_PER_DAY`) can it hold before overflowing
792                // i64::MAX?
793                // It should also not exceed `remaining_days` to bring it from positive to negative.
794                // When `remaining_days` is larger than `i64::MAX`, just limit by `i64::MAX` (no-op)
795                let extra_days = ((i64::MAX - usecs) / USECS_PER_DAY)
796                    .min(remaining_days.try_into().unwrap_or(i64::MAX));
797                // The lhs of `min` ensures `extra_days * USECS_PER_DAY <= i64::MAX - usecs`
798                usecs += extra_days * USECS_PER_DAY;
799                // The rhs of `min` ensures `extra_days <= remaining_days`
800                remaining_days -= extra_days as i128;
801
802                // Similar above
803                let mut days = (remaining_days % 30) as i32;
804                let mut remaining_months = remaining_days / 30;
805                let extra_months =
806                    ((i32::MAX - days) / 30).min(remaining_months.try_into().unwrap_or(i32::MAX));
807                days += extra_months * 30;
808                remaining_months -= extra_months as i128;
809
810                let months = remaining_months.try_into().ok()?;
811                Some(Interval::from_month_day_usec(months, days, usecs))
812            }
813            Ordering::Less => {
814                let remaining_usecs = self.0;
815                let mut usecs = (remaining_usecs % (USECS_PER_DAY as i128)) as i64;
816                let mut remaining_days = remaining_usecs / (USECS_PER_DAY as i128);
817                // The negative case. Borrow negative `extra_days` to make `usecs` as close to
818                // `i64::MIN` as possible.
819                let extra_days = ((i64::MIN - usecs) / USECS_PER_DAY)
820                    .max(remaining_days.try_into().unwrap_or(i64::MIN));
821                usecs += extra_days * USECS_PER_DAY;
822                remaining_days -= extra_days as i128;
823
824                let mut days = (remaining_days % 30) as i32;
825                let mut remaining_months = remaining_days / 30;
826                let extra_months =
827                    ((i32::MIN - days) / 30).max(remaining_months.try_into().unwrap_or(i32::MIN));
828                days += extra_months * 30;
829                remaining_months -= extra_months as i128;
830
831                let months = remaining_months.try_into().ok()?;
832                Some(Interval::from_month_day_usec(months, days, usecs))
833            }
834        }
835    }
836}
837
838impl<'de> Deserialize<'de> for Interval {
839    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
840    where
841        D: serde::Deserializer<'de>,
842    {
843        let cmp_value = IntervalCmpValue(i128::deserialize(deserializer)?);
844        let interval = cmp_value
845            .as_justified()
846            .or_else(|| cmp_value.as_alternate());
847        interval.ok_or_else(|| {
848            use serde::de::Error as _;
849            D::Error::custom("memcomparable deserialize interval overflow")
850        })
851    }
852}
853
854impl crate::hash::HashKeySer<'_> for Interval {
855    fn serialize_into(self, mut buf: impl BufMut) {
856        let cmp_value = IntervalCmpValue::from(self);
857        let b = cmp_value.0.to_ne_bytes();
858        buf.put_slice(&b);
859    }
860
861    fn exact_size() -> Option<usize> {
862        Some(16)
863    }
864}
865
866impl crate::hash::HashKeyDe for Interval {
867    fn deserialize(_data_type: &DataType, mut buf: impl Buf) -> Self {
868        let value = buf.get_i128_ne();
869        let cmp_value = IntervalCmpValue(value);
870        cmp_value
871            .as_justified()
872            .or_else(|| cmp_value.as_alternate())
873            .expect("HashKey deserialize interval overflow")
874    }
875}
876
877/// Duplicated logic only used by `HopWindow`. See #8452.
878#[expect(clippy::from_over_into)]
879impl Into<PbInterval> for Interval {
880    fn into(self) -> PbInterval {
881        PbInterval {
882            months: self.months,
883            days: self.days,
884            usecs: self.usecs,
885        }
886    }
887}
888
889impl From<&'_ PbInterval> for Interval {
890    fn from(p: &'_ PbInterval) -> Self {
891        Self {
892            months: p.months,
893            days: p.days,
894            usecs: p.usecs,
895        }
896    }
897}
898
899impl From<Time> for Interval {
900    fn from(time: Time) -> Self {
901        Self {
902            months: 0,
903            days: 0,
904            usecs: time.micros_of_day() as i64,
905        }
906    }
907}
908
909impl Add for Interval {
910    type Output = Self;
911
912    fn add(self, rhs: Self) -> Self {
913        let months = self.months + rhs.months;
914        let days = self.days + rhs.days;
915        let usecs = self.usecs + rhs.usecs;
916        Interval {
917            months,
918            days,
919            usecs,
920        }
921    }
922}
923
924impl CheckedNeg for Interval {
925    fn checked_neg(&self) -> Option<Self> {
926        let months = self.months.checked_neg()?;
927        let days = self.days.checked_neg()?;
928        let usecs = self.usecs.checked_neg()?;
929        Some(Interval {
930            months,
931            days,
932            usecs,
933        })
934    }
935}
936
937impl CheckedAdd for Interval {
938    fn checked_add(&self, other: &Self) -> Option<Self> {
939        let months = self.months.checked_add(other.months)?;
940        let days = self.days.checked_add(other.days)?;
941        let usecs = self.usecs.checked_add(other.usecs)?;
942        Some(Interval {
943            months,
944            days,
945            usecs,
946        })
947    }
948}
949
950impl Sub for Interval {
951    type Output = Self;
952
953    fn sub(self, rhs: Self) -> Self {
954        let months = self.months - rhs.months;
955        let days = self.days - rhs.days;
956        let usecs = self.usecs - rhs.usecs;
957        Interval {
958            months,
959            days,
960            usecs,
961        }
962    }
963}
964
965impl CheckedSub for Interval {
966    fn checked_sub(&self, other: &Self) -> Option<Self> {
967        let months = self.months.checked_sub(other.months)?;
968        let days = self.days.checked_sub(other.days)?;
969        let usecs = self.usecs.checked_sub(other.usecs)?;
970        Some(Interval {
971            months,
972            days,
973            usecs,
974        })
975    }
976}
977
978impl Zero for Interval {
979    fn zero() -> Self {
980        Self::from_month_day_usec(0, 0, 0)
981    }
982
983    fn is_zero(&self) -> bool {
984        self.months == 0 && self.days == 0 && self.usecs == 0
985    }
986}
987
988impl Neg for Interval {
989    type Output = Self;
990
991    fn neg(self) -> Self {
992        Self {
993            months: -self.months,
994            days: -self.days,
995            usecs: -self.usecs,
996        }
997    }
998}
999
1000impl ToText for crate::types::Interval {
1001    fn write<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
1002        write!(f, "{self}")
1003    }
1004
1005    fn write_with_type<W: std::fmt::Write>(&self, ty: &DataType, f: &mut W) -> std::fmt::Result {
1006        match ty {
1007            DataType::Interval => self.write(f),
1008            _ => unreachable!(),
1009        }
1010    }
1011}
1012
1013/// Error type for parsing an [`Interval`].
1014#[derive(thiserror::Error, Debug, thiserror_ext::Construct)]
1015pub enum IntervalParseError {
1016    #[error("Invalid interval: {0}")]
1017    Invalid(String),
1018
1019    #[error(
1020        "Invalid interval: {0}, expected format P<years>Y<months>M<days>DT<hours>H<minutes>M<seconds>S"
1021    )]
1022    InvalidIso8601(String),
1023
1024    #[error("Invalid unit: {0}")]
1025    InvalidUnit(String),
1026
1027    #[error("{0}")]
1028    Uncategorized(String),
1029}
1030
1031type ParseResult<T> = std::result::Result<T, IntervalParseError>;
1032
1033impl Interval {
1034    pub fn as_iso_8601(&self) -> String {
1035        // ISO pattern - PnYnMnDTnHnMnS
1036        let years = self.months / 12;
1037        let months = self.months % 12;
1038        let days = self.days;
1039        let secs_fract = (self.usecs % USECS_PER_SEC).abs();
1040        let total_secs = (self.usecs / USECS_PER_SEC).abs();
1041        let hours = total_secs / 3600;
1042        let minutes = (total_secs / 60) % 60;
1043        let seconds = total_secs % 60;
1044        let mut buf = [0u8; 7];
1045        let fract_str = if secs_fract != 0 {
1046            write!(buf.as_mut_slice(), ".{:06}", secs_fract).unwrap();
1047            std::str::from_utf8(&buf).unwrap().trim_end_matches('0')
1048        } else {
1049            ""
1050        };
1051        format!("P{years}Y{months}M{days}DT{hours}H{minutes}M{seconds}{fract_str}S")
1052    }
1053
1054    /// Converts str to interval
1055    ///
1056    /// The input str must have the following format:
1057    /// `P<years>Y<months>M<days>DT<hours>H<minutes>M<seconds>S`
1058    ///
1059    /// Example
1060    /// - P1Y2M3DT4H5M6.78S
1061    pub fn from_iso_8601(s: &str) -> ParseResult<Self> {
1062        // ISO pattern - PnYnMnDTnHnMnS
1063        static ISO_8601_REGEX: LazyLock<Regex> = LazyLock::new(|| {
1064            Regex::new(r"^P([0-9]+)Y([0-9]+)M([0-9]+)DT([0-9]+)H([0-9]+)M([0-9]+(?:\.[0-9]+)?)S$")
1065                .unwrap()
1066        });
1067        // wrap into a closure to simplify error handling
1068        let f = || {
1069            let caps = ISO_8601_REGEX.captures(s)?;
1070            let years: i32 = caps[1].parse().ok()?;
1071            let months: i32 = caps[2].parse().ok()?;
1072            let days = caps[3].parse().ok()?;
1073            let hours: i64 = caps[4].parse().ok()?;
1074            let minutes: i64 = caps[5].parse().ok()?;
1075            // usecs = sec * 1000000, use decimal to be exact
1076            let usecs: i64 = (Decimal::from_str_exact(&caps[6])
1077                .ok()?
1078                .checked_mul(Decimal::from_str_exact("1000000").unwrap()))?
1079            .try_into()
1080            .ok()?;
1081            Some(Interval::from_month_day_usec(
1082                // months = years * 12 + months
1083                years.checked_mul(12)?.checked_add(months)?,
1084                days,
1085                // usecs = (hours * 3600 + minutes * 60) * 1000000 + usecs
1086                (hours
1087                    .checked_mul(3_600)?
1088                    .checked_add(minutes.checked_mul(60)?))?
1089                .checked_mul(USECS_PER_SEC)?
1090                .checked_add(usecs)?,
1091            ))
1092        };
1093        f().ok_or_else(|| IntervalParseError::invalid_iso8601(s))
1094    }
1095}
1096
1097impl Display for Interval {
1098    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1099        let years = self.months / 12;
1100        let months = self.months % 12;
1101        let days = self.days;
1102        let mut space = false;
1103        let mut following_neg = false;
1104        let mut write_i32 = |arg: i32, unit: &str| -> std::fmt::Result {
1105            if arg == 0 {
1106                return Ok(());
1107            }
1108            if space {
1109                write!(f, " ")?;
1110            }
1111            if following_neg && arg > 0 {
1112                write!(f, "+")?;
1113            }
1114            write!(f, "{arg} {unit}")?;
1115            if arg != 1 {
1116                write!(f, "s")?;
1117            }
1118            space = true;
1119            following_neg = arg < 0;
1120            Ok(())
1121        };
1122        write_i32(years, "year")?;
1123        write_i32(months, "mon")?;
1124        write_i32(days, "day")?;
1125        if self.usecs != 0 || self.months == 0 && self.days == 0 {
1126            // `abs` on `self.usecs == i64::MIN` would overflow, so we divide first then abs
1127            let secs_fract = (self.usecs % USECS_PER_SEC).abs();
1128            let total_secs = (self.usecs / USECS_PER_SEC).abs();
1129            let hours = total_secs / 3600;
1130            let minutes = (total_secs / 60) % 60;
1131            let seconds = total_secs % 60;
1132
1133            if space {
1134                write!(f, " ")?;
1135            }
1136            if following_neg && self.usecs > 0 {
1137                write!(f, "+")?;
1138            } else if self.usecs < 0 {
1139                write!(f, "-")?;
1140            }
1141            write!(f, "{hours:0>2}:{minutes:0>2}:{seconds:0>2}")?;
1142            if secs_fract != 0 {
1143                let mut buf = [0u8; 7];
1144                write!(buf.as_mut_slice(), ".{:06}", secs_fract).unwrap();
1145                write!(
1146                    f,
1147                    "{}",
1148                    std::str::from_utf8(&buf).unwrap().trim_end_matches('0')
1149                )?;
1150            }
1151        }
1152        Ok(())
1153    }
1154}
1155
1156impl ToSql for Interval {
1157    to_sql_checked!();
1158
1159    fn to_sql(
1160        &self,
1161        _: &Type,
1162        out: &mut BytesMut,
1163    ) -> std::result::Result<IsNull, Box<dyn Error + 'static + Send + Sync>> {
1164        // refer: https://github.com/postgres/postgres/blob/517bf2d91/src/backend/utils/adt/timestamp.c#L1008
1165        out.put_i64(self.usecs);
1166        out.put_i32(self.days);
1167        out.put_i32(self.months);
1168        Ok(IsNull::No)
1169    }
1170
1171    fn accepts(ty: &Type) -> bool {
1172        matches!(*ty, Type::INTERVAL)
1173    }
1174}
1175
1176impl<'a> FromSql<'a> for Interval {
1177    fn from_sql(
1178        _: &Type,
1179        mut raw: &'a [u8],
1180    ) -> std::result::Result<Interval, Box<dyn Error + Sync + Send>> {
1181        let usecs = raw.read_i64::<NetworkEndian>()?;
1182        let days = raw.read_i32::<NetworkEndian>()?;
1183        let months = raw.read_i32::<NetworkEndian>()?;
1184        Ok(Interval::from_month_day_usec(months, days, usecs))
1185    }
1186
1187    fn accepts(ty: &Type) -> bool {
1188        matches!(*ty, Type::INTERVAL)
1189    }
1190}
1191
1192#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1193pub enum DateTimeField {
1194    Year,
1195    Month,
1196    Day,
1197    Hour,
1198    Minute,
1199    Second,
1200}
1201
1202impl FromStr for DateTimeField {
1203    type Err = IntervalParseError;
1204
1205    fn from_str(s: &str) -> ParseResult<Self> {
1206        match s.to_lowercase().as_str() {
1207            "years" | "year" | "yrs" | "yr" | "y" => Ok(Self::Year),
1208            "days" | "day" | "d" => Ok(Self::Day),
1209            "hours" | "hour" | "hrs" | "hr" | "h" => Ok(Self::Hour),
1210            "minutes" | "minute" | "mins" | "min" | "m" => Ok(Self::Minute),
1211            "months" | "month" | "mons" | "mon" => Ok(Self::Month),
1212            "seconds" | "second" | "secs" | "sec" | "s" => Ok(Self::Second),
1213            _ => Err(IntervalParseError::invalid_unit(s)),
1214        }
1215    }
1216}
1217
1218#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1219enum TimeStrToken {
1220    Second(F64),
1221    Num(i64),
1222    TimeUnit(DateTimeField),
1223}
1224
1225fn parse_interval(s: &str) -> ParseResult<Vec<TimeStrToken>> {
1226    let s = s.trim();
1227    let mut tokens = Vec::new();
1228    let mut num_buf = "".to_owned();
1229    let mut char_buf = "".to_owned();
1230    let mut hour_min_sec = Vec::new();
1231    for (i, c) in s.chars().enumerate() {
1232        match c {
1233            '-' | '+' => {
1234                num_buf.push(c);
1235            }
1236            '.' => {
1237                num_buf.push(c);
1238            }
1239            c if c.is_ascii_digit() => {
1240                convert_unit(&mut char_buf, &mut tokens)?;
1241                num_buf.push(c);
1242            }
1243            c if c.is_ascii_alphabetic() => {
1244                convert_digit(&mut num_buf, &mut tokens)?;
1245                char_buf.push(c);
1246            }
1247            chr if chr.is_ascii_whitespace() => {
1248                convert_unit(&mut char_buf, &mut tokens)?;
1249                // Skip parsing standalone '+' or '-' signs until they combine with digits.
1250                if !matches!(num_buf.as_str(), "-" | "+") {
1251                    convert_digit(&mut num_buf, &mut tokens)?;
1252                }
1253            }
1254            ':' => {
1255                // there must be a digit before the ':'
1256                if num_buf.is_empty() {
1257                    return Err(IntervalParseError::invalid(s));
1258                }
1259                hour_min_sec.push(num_buf.clone());
1260                num_buf.clear();
1261            }
1262            _ => {
1263                return Err(IntervalParseError::uncategorized(format!(
1264                    "Invalid character at offset {} in {}: {:?}. Only support digit or alphabetic now",
1265                    i, s, c
1266                )));
1267            }
1268        };
1269    }
1270    if !hour_min_sec.is_empty() {
1271        if !num_buf.is_empty() {
1272            hour_min_sec.push(num_buf.clone());
1273            num_buf.clear();
1274        }
1275    } else {
1276        convert_digit(&mut num_buf, &mut tokens)?;
1277    }
1278    convert_unit(&mut char_buf, &mut tokens)?;
1279    convert_hms(&hour_min_sec, &mut tokens)
1280        .ok_or_else(|| IntervalParseError::invalid(format!("{hour_min_sec:?}")))?;
1281
1282    Ok(tokens)
1283}
1284
1285fn convert_digit(c: &mut String, t: &mut Vec<TimeStrToken>) -> ParseResult<()> {
1286    if !c.is_empty() {
1287        match c.parse::<i64>() {
1288            Ok(num) => {
1289                t.push(TimeStrToken::Num(num));
1290            }
1291            Err(_) => {
1292                return Err(IntervalParseError::invalid(c.clone()));
1293            }
1294        }
1295        c.clear();
1296    }
1297    Ok(())
1298}
1299
1300fn convert_unit(c: &mut String, t: &mut Vec<TimeStrToken>) -> ParseResult<()> {
1301    if !c.is_empty() {
1302        t.push(TimeStrToken::TimeUnit(c.parse()?));
1303        c.clear();
1304    }
1305    Ok(())
1306}
1307
1308/// convert `hour_min_sec` format
1309/// e.g.
1310/// c = ["1", "2", "3"], c will be convert to:
1311/// [`TimeStrToken::Num(1)`, `TimeStrToken::TimeUnit(DateTimeField::Hour)`,
1312///  `TimeStrToken::Num(2)`, `TimeStrToken::TimeUnit(DateTimeField::Minute)`,
1313///  `TimeStrToken::Second("3")`, `TimeStrToken::TimeUnit(DateTimeField::Second)`]
1314fn convert_hms(c: &Vec<String>, t: &mut Vec<TimeStrToken>) -> Option<()> {
1315    if c.len() > 3 {
1316        return None;
1317    }
1318    let mut is_neg = false;
1319    if let Some(s) = c.first() {
1320        let v = s.parse().ok()?;
1321        is_neg = s.starts_with('-');
1322        t.push(TimeStrToken::Num(v));
1323        t.push(TimeStrToken::TimeUnit(DateTimeField::Hour))
1324    }
1325    if let Some(s) = c.get(1) {
1326        let mut v: i64 = s.parse().ok()?;
1327        if !(0..60).contains(&v) {
1328            return None;
1329        }
1330        if is_neg {
1331            v = v.checked_neg()?;
1332        }
1333        t.push(TimeStrToken::Num(v));
1334        t.push(TimeStrToken::TimeUnit(DateTimeField::Minute))
1335    }
1336    if let Some(s) = c.get(2) {
1337        let mut v: f64 = s.parse().ok()?;
1338        // PostgreSQL allows '60.x' for seconds.
1339        if !(0f64..61f64).contains(&v) {
1340            return None;
1341        }
1342        if is_neg {
1343            v = -v;
1344        }
1345        t.push(TimeStrToken::Second(v.into()));
1346        t.push(TimeStrToken::TimeUnit(DateTimeField::Second))
1347    }
1348    Some(())
1349}
1350
1351impl Interval {
1352    fn parse_sql_standard(s: &str, leading_field: DateTimeField) -> ParseResult<Self> {
1353        use DateTimeField::*;
1354        let tokens = parse_interval(s)?;
1355        // Todo: support more syntax
1356        if tokens.len() > 1 {
1357            return Err(IntervalParseError::invalid(s));
1358        }
1359        let num = match tokens.first() {
1360            Some(TimeStrToken::Num(num)) => *num,
1361            _ => {
1362                return Err(IntervalParseError::invalid(s));
1363            }
1364        };
1365
1366        (|| match leading_field {
1367            Year => {
1368                let months = num.checked_mul(12)?.try_into().ok()?;
1369                Some(Interval::from_month_day_usec(months, 0, 0))
1370            }
1371            Month => Some(Interval::from_month_day_usec(num.try_into().ok()?, 0, 0)),
1372            Day => Some(Interval::from_month_day_usec(0, num.try_into().ok()?, 0)),
1373            Hour => {
1374                let usecs = num.checked_mul(3600 * USECS_PER_SEC)?;
1375                Some(Interval::from_month_day_usec(0, 0, usecs))
1376            }
1377            Minute => {
1378                let usecs = num.checked_mul(60 * USECS_PER_SEC)?;
1379                Some(Interval::from_month_day_usec(0, 0, usecs))
1380            }
1381            Second => {
1382                let usecs = num.checked_mul(USECS_PER_SEC)?;
1383                Some(Interval::from_month_day_usec(0, 0, usecs))
1384            }
1385        })()
1386        .ok_or_else(|| IntervalParseError::invalid(s))
1387    }
1388
1389    fn parse_postgres(s: &str) -> ParseResult<Self> {
1390        use DateTimeField::*;
1391        let mut tokens = parse_interval(s)?;
1392        if tokens.len() % 2 != 0
1393            && let Some(TimeStrToken::Num(_)) = tokens.last()
1394        {
1395            tokens.push(TimeStrToken::TimeUnit(DateTimeField::Second));
1396        }
1397        if tokens.len() % 2 != 0 {
1398            return Err(IntervalParseError::invalid(s));
1399        }
1400        let mut token_iter = tokens.into_iter();
1401        let mut result = Interval::from_month_day_usec(0, 0, 0);
1402        while let Some(num) = token_iter.next()
1403            && let Some(interval_unit) = token_iter.next()
1404        {
1405            match (num, interval_unit) {
1406                (TimeStrToken::Num(num), TimeStrToken::TimeUnit(interval_unit)) => {
1407                    result = (|| match interval_unit {
1408                        Year => {
1409                            let months = num.checked_mul(12)?.try_into().ok()?;
1410                            Some(Interval::from_month_day_usec(months, 0, 0))
1411                        }
1412                        Month => Some(Interval::from_month_day_usec(num.try_into().ok()?, 0, 0)),
1413                        Day => Some(Interval::from_month_day_usec(0, num.try_into().ok()?, 0)),
1414                        Hour => {
1415                            let usecs = num.checked_mul(3600 * USECS_PER_SEC)?;
1416                            Some(Interval::from_month_day_usec(0, 0, usecs))
1417                        }
1418                        Minute => {
1419                            let usecs = num.checked_mul(60 * USECS_PER_SEC)?;
1420                            Some(Interval::from_month_day_usec(0, 0, usecs))
1421                        }
1422                        Second => {
1423                            let usecs = num.checked_mul(USECS_PER_SEC)?;
1424                            Some(Interval::from_month_day_usec(0, 0, usecs))
1425                        }
1426                    })()
1427                    .and_then(|rhs| result.checked_add(&rhs))
1428                    .ok_or_else(|| IntervalParseError::invalid(s))?;
1429                }
1430                (TimeStrToken::Second(second), TimeStrToken::TimeUnit(interval_unit)) => {
1431                    result = match interval_unit {
1432                        Second => {
1433                            // If unsatisfied precision is passed as input, we should not return
1434                            // None (Error).
1435                            let usecs = (second.into_inner() * (USECS_PER_SEC as f64))
1436                                .round_ties_even() as i64;
1437                            Some(Interval::from_month_day_usec(0, 0, usecs))
1438                        }
1439                        _ => None,
1440                    }
1441                    .and_then(|rhs| result.checked_add(&rhs))
1442                    .ok_or_else(|| IntervalParseError::invalid(s))?;
1443                }
1444                _ => {
1445                    return Err(IntervalParseError::invalid(s));
1446                }
1447            }
1448        }
1449        Ok(result)
1450    }
1451
1452    pub fn parse_with_fields(s: &str, leading_field: Option<DateTimeField>) -> ParseResult<Self> {
1453        if let Some(leading_field) = leading_field {
1454            Self::parse_sql_standard(s, leading_field)
1455        } else {
1456            match s.as_bytes().get(0) {
1457                Some(b'P') => Self::from_iso_8601(s),
1458                _ => Self::parse_postgres(s),
1459            }
1460        }
1461    }
1462}
1463
1464impl FromStr for Interval {
1465    type Err = IntervalParseError;
1466
1467    fn from_str(s: &str) -> ParseResult<Self> {
1468        Self::parse_with_fields(s, None)
1469    }
1470}
1471
1472#[cfg(test)]
1473mod tests {
1474    use interval::test_utils::IntervalTestExt;
1475
1476    use super::*;
1477    use crate::types::ordered_float::OrderedFloat;
1478    use crate::util::panic::rw_catch_unwind;
1479
1480    #[test]
1481    fn test_parse() {
1482        let interval = "04:00:00".parse::<Interval>().unwrap();
1483        assert_eq!(interval, Interval::from_millis(4 * 3600 * 1000));
1484
1485        let interval = "1 year 2 months 3 days 00:00:01"
1486            .parse::<Interval>()
1487            .unwrap();
1488        assert_eq!(
1489            interval,
1490            Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1000)
1491        );
1492
1493        let interval = "1 year 2 months 3 days 00:00:00.001"
1494            .parse::<Interval>()
1495            .unwrap();
1496        assert_eq!(
1497            interval,
1498            Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1)
1499        );
1500
1501        let interval = "1 year 2 months 3 days 00:59:59.005"
1502            .parse::<Interval>()
1503            .unwrap();
1504        assert_eq!(
1505            interval,
1506            Interval::from_month(14)
1507                + Interval::from_days(3)
1508                + Interval::from_minutes(59)
1509                + Interval::from_millis(59000)
1510                + Interval::from_millis(5)
1511        );
1512
1513        let interval = "1 year 2 months 3 days 01".parse::<Interval>().unwrap();
1514        assert_eq!(
1515            interval,
1516            Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1000)
1517        );
1518
1519        let interval = "1 year 2 months 3 days 1:".parse::<Interval>().unwrap();
1520        assert_eq!(
1521            interval,
1522            Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(60)
1523        );
1524
1525        let interval = "1 year 2 months 3 days 1:2".parse::<Interval>().unwrap();
1526        assert_eq!(
1527            interval,
1528            Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(62)
1529        );
1530
1531        let interval = "1 year 2 months 3 days 1:2:".parse::<Interval>().unwrap();
1532        assert_eq!(
1533            interval,
1534            Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(62)
1535        );
1536
1537        let interval = "P1Y2M3DT0H5M0S".parse::<Interval>().unwrap();
1538        assert_eq!(
1539            interval,
1540            Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(5)
1541        );
1542    }
1543
1544    #[test]
1545    fn test_to_string() {
1546        assert_eq!(
1547            Interval::from_month_day_usec(-14, 3, (11 * 3600 + 45 * 60 + 14) * USECS_PER_SEC + 233)
1548                .to_string(),
1549            "-1 years -2 mons +3 days 11:45:14.000233"
1550        );
1551        assert_eq!(
1552            Interval::from_month_day_usec(-14, 3, 0).to_string(),
1553            "-1 years -2 mons +3 days"
1554        );
1555        assert_eq!(Interval::default().to_string(), "00:00:00");
1556        assert_eq!(
1557            Interval::from_month_day_usec(
1558                -14,
1559                3,
1560                -((11 * 3600 + 45 * 60 + 14) * USECS_PER_SEC + 233)
1561            )
1562            .to_string(),
1563            "-1 years -2 mons +3 days -11:45:14.000233"
1564        );
1565    }
1566
1567    #[test]
1568    fn test_exact_div() {
1569        let cases = [
1570            ((14, 6, 6), (14, 6, 6), Some(1)),
1571            ((0, 0, 0), (0, 0, 0), None),
1572            ((0, 0, 0), (1, 0, 0), Some(0)),
1573            ((1, 1, 1), (0, 0, 0), None),
1574            ((1, 1, 1), (1, 0, 0), None),
1575            ((10, 0, 0), (1, 0, 0), Some(10)),
1576            ((10, 0, 0), (4, 0, 0), None),
1577            ((0, 24, 0), (4, 0, 0), None),
1578            ((6, 8, 9), (3, 1, 3), None),
1579            ((6, 8, 12), (3, 4, 6), Some(2)),
1580        ];
1581
1582        for (lhs, rhs, expected) in cases {
1583            let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1584            let rhs = Interval::from_month_day_usec(rhs.0, rhs.1, rhs.2 as i64);
1585            let result = rw_catch_unwind(|| {
1586                let actual = lhs.exact_div(&rhs);
1587                assert_eq!(actual, expected);
1588            });
1589            if result.is_err() {
1590                println!("Failed on {}.exact_div({})", lhs, rhs);
1591                break;
1592            }
1593        }
1594    }
1595
1596    #[test]
1597    fn test_div_float() {
1598        let cases_int = [
1599            ((10, 8, 6), 2, Some((5, 4, 3))),
1600            ((1, 2, 33), 3, Some((0, 10, 57600000011i64))),
1601            ((1, 0, 11), 10, Some((0, 3, 1))),
1602            ((5, 6, 7), 0, None),
1603        ];
1604
1605        let cases_float = [
1606            ((10, 8, 6), 2.0f32, Some((5, 4, 3))),
1607            ((1, 2, 33), 3.0f32, Some((0, 10, 57600000011i64))),
1608            ((10, 15, 100), 2.5f32, Some((4, 6, 40))),
1609            ((5, 6, 7), 0.0f32, None),
1610        ];
1611
1612        for (lhs, rhs, expected) in cases_int {
1613            let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1614            let expected = expected.map(|x| Interval::from_month_day_usec(x.0, x.1, x.2));
1615
1616            let actual = lhs.div_float(rhs as i16);
1617            assert_eq!(actual, expected);
1618
1619            let actual = lhs.div_float(rhs);
1620            assert_eq!(actual, expected);
1621
1622            let actual = lhs.div_float(rhs as i64);
1623            assert_eq!(actual, expected);
1624        }
1625
1626        for (lhs, rhs, expected) in cases_float {
1627            let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1628            let expected = expected.map(|x| Interval::from_month_day_usec(x.0, x.1, x.2));
1629
1630            let actual = lhs.div_float(OrderedFloat::<f32>(rhs));
1631            assert_eq!(actual, expected);
1632
1633            let actual = lhs.div_float(OrderedFloat::<f64>(rhs as f64));
1634            assert_eq!(actual, expected);
1635        }
1636    }
1637
1638    #[test]
1639    fn test_serialize_deserialize() {
1640        let mut serializer = memcomparable::Serializer::new(vec![]);
1641        let a = Interval::from_month_day_usec(123, 456, 789);
1642        a.serialize(&mut serializer).unwrap();
1643        let buf = serializer.into_inner();
1644        let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1645        assert_eq!(Interval::deserialize(&mut deserializer).unwrap(), a);
1646    }
1647
1648    #[test]
1649    fn test_memcomparable() {
1650        let cases = [
1651            ((1, 2, 3), (4, 5, 6), Ordering::Less),
1652            ((0, 31, 0), (1, 0, 0), Ordering::Greater),
1653            ((1, 0, 0), (0, 0, USECS_PER_MONTH + 1), Ordering::Less),
1654            ((0, 1, 0), (0, 0, USECS_PER_DAY + 1), Ordering::Less),
1655            (
1656                (2, 3, 4),
1657                (1, 2, 4 + USECS_PER_DAY + USECS_PER_MONTH),
1658                Ordering::Equal,
1659            ),
1660        ];
1661
1662        for ((lhs_months, lhs_days, lhs_usecs), (rhs_months, rhs_days, rhs_usecs), order) in cases {
1663            let lhs = {
1664                let mut serializer = memcomparable::Serializer::new(vec![]);
1665                Interval::from_month_day_usec(lhs_months, lhs_days, lhs_usecs)
1666                    .serialize(&mut serializer)
1667                    .unwrap();
1668                serializer.into_inner()
1669            };
1670            let rhs = {
1671                let mut serializer = memcomparable::Serializer::new(vec![]);
1672                Interval::from_month_day_usec(rhs_months, rhs_days, rhs_usecs)
1673                    .serialize(&mut serializer)
1674                    .unwrap();
1675                serializer.into_inner()
1676            };
1677            assert_eq!(lhs.cmp(&rhs), order)
1678        }
1679    }
1680
1681    #[test]
1682    fn test_deserialize_justify() {
1683        let cases = [
1684            (
1685                (0, 0, USECS_PER_MONTH * 2 + USECS_PER_DAY * 3 + 4),
1686                Some((2, 3, 4i64, "2 mons 3 days 00:00:00.000004")),
1687            ),
1688            ((i32::MIN, i32::MIN, i64::MIN), None),
1689            ((i32::MAX, i32::MAX, i64::MAX), None),
1690            (
1691                (0, i32::MIN, i64::MIN),
1692                Some((
1693                    -75141187,
1694                    -29,
1695                    -14454775808,
1696                    "-6261765 years -7 mons -29 days -04:00:54.775808",
1697                )),
1698            ),
1699            (
1700                (i32::MIN, -60, i64::MAX),
1701                Some((
1702                    -2143925250,
1703                    -8,
1704                    -71945224193,
1705                    "-178660437 years -6 mons -8 days -19:59:05.224193",
1706                )),
1707            ),
1708        ];
1709        for ((lhs_months, lhs_days, lhs_usecs), rhs) in cases {
1710            let input = Interval::from_month_day_usec(lhs_months, lhs_days, lhs_usecs);
1711            let actual_deserialize = IntervalCmpValue::from(input).as_justified();
1712
1713            match rhs {
1714                None => {
1715                    assert_eq!(actual_deserialize, None);
1716                }
1717                Some((rhs_months, rhs_days, rhs_usecs, rhs_str)) => {
1718                    // We should test individual fields rather than using custom `Eq`
1719                    assert_eq!(actual_deserialize.unwrap().months(), rhs_months);
1720                    assert_eq!(actual_deserialize.unwrap().days(), rhs_days);
1721                    assert_eq!(actual_deserialize.unwrap().usecs(), rhs_usecs);
1722                    assert_eq!(actual_deserialize.unwrap().to_string(), rhs_str);
1723                }
1724            }
1725        }
1726
1727        // A false positive overflow that is buggy in PostgreSQL 15.2.
1728        let input = Interval::from_month_day_usec(i32::MIN, -30, 1);
1729        let actual_deserialize = IntervalCmpValue::from(input).as_justified();
1730        // It has a justified interval within range, and can be obtained by our deserialization.
1731        assert_eq!(actual_deserialize.unwrap().months(), i32::MIN);
1732        assert_eq!(actual_deserialize.unwrap().days(), -29);
1733        assert_eq!(actual_deserialize.unwrap().usecs(), -USECS_PER_DAY + 1);
1734    }
1735
1736    #[test]
1737    fn test_deserialize_alternate() {
1738        let cases = [
1739            (0, 0, USECS_PER_MONTH * 2 + USECS_PER_DAY * 3 + 4),
1740            (i32::MIN, i32::MIN, i64::MIN),
1741            (i32::MAX, i32::MAX, i64::MAX),
1742            (0, i32::MIN, i64::MIN),
1743            (i32::MIN, -60, i64::MAX),
1744        ];
1745        for (months, days, usecs) in cases {
1746            let input = Interval::from_month_day_usec(months, days, usecs);
1747
1748            let mut serializer = memcomparable::Serializer::new(vec![]);
1749            input.serialize(&mut serializer).unwrap();
1750            let buf = serializer.into_inner();
1751            let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1752            let actual = Interval::deserialize(&mut deserializer).unwrap();
1753
1754            // The Interval we get back can be a different one, but they should be equal.
1755            assert_eq!(actual, input);
1756        }
1757
1758        // Decoding invalid value
1759        let mut serializer = memcomparable::Serializer::new(vec![]);
1760        (i64::MAX, u64::MAX).serialize(&mut serializer).unwrap();
1761        let buf = serializer.into_inner();
1762        let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1763        assert!(Interval::deserialize(&mut deserializer).is_err());
1764
1765        let buf = i128::MIN.to_ne_bytes();
1766        rw_catch_unwind(|| {
1767            <Interval as crate::hash::HashKeyDe>::deserialize(&DataType::Interval, &mut &buf[..])
1768        })
1769        .unwrap_err();
1770    }
1771
1772    #[test]
1773    fn test_interval_estimate_size() {
1774        let interval = Interval::MIN;
1775        assert_eq!(interval.estimated_size(), 16);
1776    }
1777
1778    #[test]
1779    fn test_iso_8601() {
1780        let iso_8601_str = "P1Y2M3DT4H5M6.789123S";
1781        let lhs = Interval::from_month_day_usec(14, 3, 14706789123);
1782        let rhs = Interval::from_iso_8601(iso_8601_str).unwrap();
1783        assert_eq!(rhs.as_iso_8601().as_str(), iso_8601_str);
1784        assert_eq!(lhs, rhs);
1785    }
1786}