risingwave_common/types/
interval.rs

1// Copyright 2025 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        let mut usecs: i64 = (time.0.num_seconds_from_midnight() as i64) * USECS_PER_SEC;
902        usecs += (time.0.nanosecond() / 1000) as i64;
903        Self {
904            months: 0,
905            days: 0,
906            usecs,
907        }
908    }
909}
910
911impl Add for Interval {
912    type Output = Self;
913
914    fn add(self, rhs: Self) -> Self {
915        let months = self.months + rhs.months;
916        let days = self.days + rhs.days;
917        let usecs = self.usecs + rhs.usecs;
918        Interval {
919            months,
920            days,
921            usecs,
922        }
923    }
924}
925
926impl CheckedNeg for Interval {
927    fn checked_neg(&self) -> Option<Self> {
928        let months = self.months.checked_neg()?;
929        let days = self.days.checked_neg()?;
930        let usecs = self.usecs.checked_neg()?;
931        Some(Interval {
932            months,
933            days,
934            usecs,
935        })
936    }
937}
938
939impl CheckedAdd for Interval {
940    fn checked_add(&self, other: &Self) -> Option<Self> {
941        let months = self.months.checked_add(other.months)?;
942        let days = self.days.checked_add(other.days)?;
943        let usecs = self.usecs.checked_add(other.usecs)?;
944        Some(Interval {
945            months,
946            days,
947            usecs,
948        })
949    }
950}
951
952impl Sub for Interval {
953    type Output = Self;
954
955    fn sub(self, rhs: Self) -> Self {
956        let months = self.months - rhs.months;
957        let days = self.days - rhs.days;
958        let usecs = self.usecs - rhs.usecs;
959        Interval {
960            months,
961            days,
962            usecs,
963        }
964    }
965}
966
967impl CheckedSub for Interval {
968    fn checked_sub(&self, other: &Self) -> Option<Self> {
969        let months = self.months.checked_sub(other.months)?;
970        let days = self.days.checked_sub(other.days)?;
971        let usecs = self.usecs.checked_sub(other.usecs)?;
972        Some(Interval {
973            months,
974            days,
975            usecs,
976        })
977    }
978}
979
980impl Zero for Interval {
981    fn zero() -> Self {
982        Self::from_month_day_usec(0, 0, 0)
983    }
984
985    fn is_zero(&self) -> bool {
986        self.months == 0 && self.days == 0 && self.usecs == 0
987    }
988}
989
990impl Neg for Interval {
991    type Output = Self;
992
993    fn neg(self) -> Self {
994        Self {
995            months: -self.months,
996            days: -self.days,
997            usecs: -self.usecs,
998        }
999    }
1000}
1001
1002impl ToText for crate::types::Interval {
1003    fn write<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
1004        write!(f, "{self}")
1005    }
1006
1007    fn write_with_type<W: std::fmt::Write>(&self, ty: &DataType, f: &mut W) -> std::fmt::Result {
1008        match ty {
1009            DataType::Interval => self.write(f),
1010            _ => unreachable!(),
1011        }
1012    }
1013}
1014
1015/// Error type for parsing an [`Interval`].
1016#[derive(thiserror::Error, Debug, thiserror_ext::Construct)]
1017pub enum IntervalParseError {
1018    #[error("Invalid interval: {0}")]
1019    Invalid(String),
1020
1021    #[error(
1022        "Invalid interval: {0}, expected format P<years>Y<months>M<days>DT<hours>H<minutes>M<seconds>S"
1023    )]
1024    InvalidIso8601(String),
1025
1026    #[error("Invalid unit: {0}")]
1027    InvalidUnit(String),
1028
1029    #[error("{0}")]
1030    Uncategorized(String),
1031}
1032
1033type ParseResult<T> = std::result::Result<T, IntervalParseError>;
1034
1035impl Interval {
1036    pub fn as_iso_8601(&self) -> String {
1037        // ISO pattern - PnYnMnDTnHnMnS
1038        let years = self.months / 12;
1039        let months = self.months % 12;
1040        let days = self.days;
1041        let secs_fract = (self.usecs % USECS_PER_SEC).abs();
1042        let total_secs = (self.usecs / USECS_PER_SEC).abs();
1043        let hours = total_secs / 3600;
1044        let minutes = (total_secs / 60) % 60;
1045        let seconds = total_secs % 60;
1046        let mut buf = [0u8; 7];
1047        let fract_str = if secs_fract != 0 {
1048            write!(buf.as_mut_slice(), ".{:06}", secs_fract).unwrap();
1049            std::str::from_utf8(&buf).unwrap().trim_end_matches('0')
1050        } else {
1051            ""
1052        };
1053        format!("P{years}Y{months}M{days}DT{hours}H{minutes}M{seconds}{fract_str}S")
1054    }
1055
1056    /// Converts str to interval
1057    ///
1058    /// The input str must have the following format:
1059    /// `P<years>Y<months>M<days>DT<hours>H<minutes>M<seconds>S`
1060    ///
1061    /// Example
1062    /// - P1Y2M3DT4H5M6.78S
1063    pub fn from_iso_8601(s: &str) -> ParseResult<Self> {
1064        // ISO pattern - PnYnMnDTnHnMnS
1065        static ISO_8601_REGEX: LazyLock<Regex> = LazyLock::new(|| {
1066            Regex::new(r"^P([0-9]+)Y([0-9]+)M([0-9]+)DT([0-9]+)H([0-9]+)M([0-9]+(?:\.[0-9]+)?)S$")
1067                .unwrap()
1068        });
1069        // wrap into a closure to simplify error handling
1070        let f = || {
1071            let caps = ISO_8601_REGEX.captures(s)?;
1072            let years: i32 = caps[1].parse().ok()?;
1073            let months: i32 = caps[2].parse().ok()?;
1074            let days = caps[3].parse().ok()?;
1075            let hours: i64 = caps[4].parse().ok()?;
1076            let minutes: i64 = caps[5].parse().ok()?;
1077            // usecs = sec * 1000000, use decimal to be exact
1078            let usecs: i64 = (Decimal::from_str_exact(&caps[6])
1079                .ok()?
1080                .checked_mul(Decimal::from_str_exact("1000000").unwrap()))?
1081            .try_into()
1082            .ok()?;
1083            Some(Interval::from_month_day_usec(
1084                // months = years * 12 + months
1085                years.checked_mul(12)?.checked_add(months)?,
1086                days,
1087                // usecs = (hours * 3600 + minutes * 60) * 1000000 + usecs
1088                (hours
1089                    .checked_mul(3_600)?
1090                    .checked_add(minutes.checked_mul(60)?))?
1091                .checked_mul(USECS_PER_SEC)?
1092                .checked_add(usecs)?,
1093            ))
1094        };
1095        f().ok_or_else(|| IntervalParseError::invalid_iso8601(s))
1096    }
1097}
1098
1099impl Display for Interval {
1100    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1101        let years = self.months / 12;
1102        let months = self.months % 12;
1103        let days = self.days;
1104        let mut space = false;
1105        let mut following_neg = false;
1106        let mut write_i32 = |arg: i32, unit: &str| -> std::fmt::Result {
1107            if arg == 0 {
1108                return Ok(());
1109            }
1110            if space {
1111                write!(f, " ")?;
1112            }
1113            if following_neg && arg > 0 {
1114                write!(f, "+")?;
1115            }
1116            write!(f, "{arg} {unit}")?;
1117            if arg != 1 {
1118                write!(f, "s")?;
1119            }
1120            space = true;
1121            following_neg = arg < 0;
1122            Ok(())
1123        };
1124        write_i32(years, "year")?;
1125        write_i32(months, "mon")?;
1126        write_i32(days, "day")?;
1127        if self.usecs != 0 || self.months == 0 && self.days == 0 {
1128            // `abs` on `self.usecs == i64::MIN` would overflow, so we divide first then abs
1129            let secs_fract = (self.usecs % USECS_PER_SEC).abs();
1130            let total_secs = (self.usecs / USECS_PER_SEC).abs();
1131            let hours = total_secs / 3600;
1132            let minutes = (total_secs / 60) % 60;
1133            let seconds = total_secs % 60;
1134
1135            if space {
1136                write!(f, " ")?;
1137            }
1138            if following_neg && self.usecs > 0 {
1139                write!(f, "+")?;
1140            } else if self.usecs < 0 {
1141                write!(f, "-")?;
1142            }
1143            write!(f, "{hours:0>2}:{minutes:0>2}:{seconds:0>2}")?;
1144            if secs_fract != 0 {
1145                let mut buf = [0u8; 7];
1146                write!(buf.as_mut_slice(), ".{:06}", secs_fract).unwrap();
1147                write!(
1148                    f,
1149                    "{}",
1150                    std::str::from_utf8(&buf).unwrap().trim_end_matches('0')
1151                )?;
1152            }
1153        }
1154        Ok(())
1155    }
1156}
1157
1158impl ToSql for Interval {
1159    to_sql_checked!();
1160
1161    fn to_sql(
1162        &self,
1163        _: &Type,
1164        out: &mut BytesMut,
1165    ) -> std::result::Result<IsNull, Box<dyn Error + 'static + Send + Sync>> {
1166        // refer: https://github.com/postgres/postgres/blob/517bf2d91/src/backend/utils/adt/timestamp.c#L1008
1167        out.put_i64(self.usecs);
1168        out.put_i32(self.days);
1169        out.put_i32(self.months);
1170        Ok(IsNull::No)
1171    }
1172
1173    fn accepts(ty: &Type) -> bool {
1174        matches!(*ty, Type::INTERVAL)
1175    }
1176}
1177
1178impl<'a> FromSql<'a> for Interval {
1179    fn from_sql(
1180        _: &Type,
1181        mut raw: &'a [u8],
1182    ) -> std::result::Result<Interval, Box<dyn Error + Sync + Send>> {
1183        let usecs = raw.read_i64::<NetworkEndian>()?;
1184        let days = raw.read_i32::<NetworkEndian>()?;
1185        let months = raw.read_i32::<NetworkEndian>()?;
1186        Ok(Interval::from_month_day_usec(months, days, usecs))
1187    }
1188
1189    fn accepts(ty: &Type) -> bool {
1190        matches!(*ty, Type::INTERVAL)
1191    }
1192}
1193
1194#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1195pub enum DateTimeField {
1196    Year,
1197    Month,
1198    Day,
1199    Hour,
1200    Minute,
1201    Second,
1202}
1203
1204impl FromStr for DateTimeField {
1205    type Err = IntervalParseError;
1206
1207    fn from_str(s: &str) -> ParseResult<Self> {
1208        match s.to_lowercase().as_str() {
1209            "years" | "year" | "yrs" | "yr" | "y" => Ok(Self::Year),
1210            "days" | "day" | "d" => Ok(Self::Day),
1211            "hours" | "hour" | "hrs" | "hr" | "h" => Ok(Self::Hour),
1212            "minutes" | "minute" | "mins" | "min" | "m" => Ok(Self::Minute),
1213            "months" | "month" | "mons" | "mon" => Ok(Self::Month),
1214            "seconds" | "second" | "secs" | "sec" | "s" => Ok(Self::Second),
1215            _ => Err(IntervalParseError::invalid_unit(s)),
1216        }
1217    }
1218}
1219
1220#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1221enum TimeStrToken {
1222    Second(F64),
1223    Num(i64),
1224    TimeUnit(DateTimeField),
1225}
1226
1227fn parse_interval(s: &str) -> ParseResult<Vec<TimeStrToken>> {
1228    let s = s.trim();
1229    let mut tokens = Vec::new();
1230    let mut num_buf = "".to_owned();
1231    let mut char_buf = "".to_owned();
1232    let mut hour_min_sec = Vec::new();
1233    for (i, c) in s.chars().enumerate() {
1234        match c {
1235            '-' | '+' => {
1236                num_buf.push(c);
1237            }
1238            '.' => {
1239                num_buf.push(c);
1240            }
1241            c if c.is_ascii_digit() => {
1242                convert_unit(&mut char_buf, &mut tokens)?;
1243                num_buf.push(c);
1244            }
1245            c if c.is_ascii_alphabetic() => {
1246                convert_digit(&mut num_buf, &mut tokens)?;
1247                char_buf.push(c);
1248            }
1249            chr if chr.is_ascii_whitespace() => {
1250                convert_unit(&mut char_buf, &mut tokens)?;
1251                // Skip parsing standalone '+' or '-' signs until they combine with digits.
1252                if !matches!(num_buf.as_str(), "-" | "+") {
1253                    convert_digit(&mut num_buf, &mut tokens)?;
1254                }
1255            }
1256            ':' => {
1257                // there must be a digit before the ':'
1258                if num_buf.is_empty() {
1259                    return Err(IntervalParseError::invalid(s));
1260                }
1261                hour_min_sec.push(num_buf.clone());
1262                num_buf.clear();
1263            }
1264            _ => {
1265                return Err(IntervalParseError::uncategorized(format!(
1266                    "Invalid character at offset {} in {}: {:?}. Only support digit or alphabetic now",
1267                    i, s, c
1268                )));
1269            }
1270        };
1271    }
1272    if !hour_min_sec.is_empty() {
1273        if !num_buf.is_empty() {
1274            hour_min_sec.push(num_buf.clone());
1275            num_buf.clear();
1276        }
1277    } else {
1278        convert_digit(&mut num_buf, &mut tokens)?;
1279    }
1280    convert_unit(&mut char_buf, &mut tokens)?;
1281    convert_hms(&hour_min_sec, &mut tokens)
1282        .ok_or_else(|| IntervalParseError::invalid(format!("{hour_min_sec:?}")))?;
1283
1284    Ok(tokens)
1285}
1286
1287fn convert_digit(c: &mut String, t: &mut Vec<TimeStrToken>) -> ParseResult<()> {
1288    if !c.is_empty() {
1289        match c.parse::<i64>() {
1290            Ok(num) => {
1291                t.push(TimeStrToken::Num(num));
1292            }
1293            Err(_) => {
1294                return Err(IntervalParseError::invalid(c.clone()));
1295            }
1296        }
1297        c.clear();
1298    }
1299    Ok(())
1300}
1301
1302fn convert_unit(c: &mut String, t: &mut Vec<TimeStrToken>) -> ParseResult<()> {
1303    if !c.is_empty() {
1304        t.push(TimeStrToken::TimeUnit(c.parse()?));
1305        c.clear();
1306    }
1307    Ok(())
1308}
1309
1310/// convert `hour_min_sec` format
1311/// e.g.
1312/// c = ["1", "2", "3"], c will be convert to:
1313/// [`TimeStrToken::Num(1)`, `TimeStrToken::TimeUnit(DateTimeField::Hour)`,
1314///  `TimeStrToken::Num(2)`, `TimeStrToken::TimeUnit(DateTimeField::Minute)`,
1315///  `TimeStrToken::Second("3")`, `TimeStrToken::TimeUnit(DateTimeField::Second)`]
1316fn convert_hms(c: &Vec<String>, t: &mut Vec<TimeStrToken>) -> Option<()> {
1317    if c.len() > 3 {
1318        return None;
1319    }
1320    let mut is_neg = false;
1321    if let Some(s) = c.first() {
1322        let v = s.parse().ok()?;
1323        is_neg = s.starts_with('-');
1324        t.push(TimeStrToken::Num(v));
1325        t.push(TimeStrToken::TimeUnit(DateTimeField::Hour))
1326    }
1327    if let Some(s) = c.get(1) {
1328        let mut v: i64 = s.parse().ok()?;
1329        if !(0..60).contains(&v) {
1330            return None;
1331        }
1332        if is_neg {
1333            v = v.checked_neg()?;
1334        }
1335        t.push(TimeStrToken::Num(v));
1336        t.push(TimeStrToken::TimeUnit(DateTimeField::Minute))
1337    }
1338    if let Some(s) = c.get(2) {
1339        let mut v: f64 = s.parse().ok()?;
1340        // PostgreSQL allows '60.x' for seconds.
1341        if !(0f64..61f64).contains(&v) {
1342            return None;
1343        }
1344        if is_neg {
1345            v = -v;
1346        }
1347        t.push(TimeStrToken::Second(v.into()));
1348        t.push(TimeStrToken::TimeUnit(DateTimeField::Second))
1349    }
1350    Some(())
1351}
1352
1353impl Interval {
1354    fn parse_sql_standard(s: &str, leading_field: DateTimeField) -> ParseResult<Self> {
1355        use DateTimeField::*;
1356        let tokens = parse_interval(s)?;
1357        // Todo: support more syntax
1358        if tokens.len() > 1 {
1359            return Err(IntervalParseError::invalid(s));
1360        }
1361        let num = match tokens.first() {
1362            Some(TimeStrToken::Num(num)) => *num,
1363            _ => {
1364                return Err(IntervalParseError::invalid(s));
1365            }
1366        };
1367
1368        (|| match leading_field {
1369            Year => {
1370                let months = num.checked_mul(12)?.try_into().ok()?;
1371                Some(Interval::from_month_day_usec(months, 0, 0))
1372            }
1373            Month => Some(Interval::from_month_day_usec(num.try_into().ok()?, 0, 0)),
1374            Day => Some(Interval::from_month_day_usec(0, num.try_into().ok()?, 0)),
1375            Hour => {
1376                let usecs = num.checked_mul(3600 * USECS_PER_SEC)?;
1377                Some(Interval::from_month_day_usec(0, 0, usecs))
1378            }
1379            Minute => {
1380                let usecs = num.checked_mul(60 * USECS_PER_SEC)?;
1381                Some(Interval::from_month_day_usec(0, 0, usecs))
1382            }
1383            Second => {
1384                let usecs = num.checked_mul(USECS_PER_SEC)?;
1385                Some(Interval::from_month_day_usec(0, 0, usecs))
1386            }
1387        })()
1388        .ok_or_else(|| IntervalParseError::invalid(s))
1389    }
1390
1391    fn parse_postgres(s: &str) -> ParseResult<Self> {
1392        use DateTimeField::*;
1393        let mut tokens = parse_interval(s)?;
1394        if tokens.len() % 2 != 0
1395            && let Some(TimeStrToken::Num(_)) = tokens.last()
1396        {
1397            tokens.push(TimeStrToken::TimeUnit(DateTimeField::Second));
1398        }
1399        if tokens.len() % 2 != 0 {
1400            return Err(IntervalParseError::invalid(s));
1401        }
1402        let mut token_iter = tokens.into_iter();
1403        let mut result = Interval::from_month_day_usec(0, 0, 0);
1404        while let Some(num) = token_iter.next()
1405            && let Some(interval_unit) = token_iter.next()
1406        {
1407            match (num, interval_unit) {
1408                (TimeStrToken::Num(num), TimeStrToken::TimeUnit(interval_unit)) => {
1409                    result = (|| match interval_unit {
1410                        Year => {
1411                            let months = num.checked_mul(12)?.try_into().ok()?;
1412                            Some(Interval::from_month_day_usec(months, 0, 0))
1413                        }
1414                        Month => Some(Interval::from_month_day_usec(num.try_into().ok()?, 0, 0)),
1415                        Day => Some(Interval::from_month_day_usec(0, num.try_into().ok()?, 0)),
1416                        Hour => {
1417                            let usecs = num.checked_mul(3600 * USECS_PER_SEC)?;
1418                            Some(Interval::from_month_day_usec(0, 0, usecs))
1419                        }
1420                        Minute => {
1421                            let usecs = num.checked_mul(60 * USECS_PER_SEC)?;
1422                            Some(Interval::from_month_day_usec(0, 0, usecs))
1423                        }
1424                        Second => {
1425                            let usecs = num.checked_mul(USECS_PER_SEC)?;
1426                            Some(Interval::from_month_day_usec(0, 0, usecs))
1427                        }
1428                    })()
1429                    .and_then(|rhs| result.checked_add(&rhs))
1430                    .ok_or_else(|| IntervalParseError::invalid(s))?;
1431                }
1432                (TimeStrToken::Second(second), TimeStrToken::TimeUnit(interval_unit)) => {
1433                    result = match interval_unit {
1434                        Second => {
1435                            // If unsatisfied precision is passed as input, we should not return
1436                            // None (Error).
1437                            let usecs = (second.into_inner() * (USECS_PER_SEC as f64))
1438                                .round_ties_even() as i64;
1439                            Some(Interval::from_month_day_usec(0, 0, usecs))
1440                        }
1441                        _ => None,
1442                    }
1443                    .and_then(|rhs| result.checked_add(&rhs))
1444                    .ok_or_else(|| IntervalParseError::invalid(s))?;
1445                }
1446                _ => {
1447                    return Err(IntervalParseError::invalid(s));
1448                }
1449            }
1450        }
1451        Ok(result)
1452    }
1453
1454    pub fn parse_with_fields(s: &str, leading_field: Option<DateTimeField>) -> ParseResult<Self> {
1455        if let Some(leading_field) = leading_field {
1456            Self::parse_sql_standard(s, leading_field)
1457        } else {
1458            match s.as_bytes().get(0) {
1459                Some(b'P') => Self::from_iso_8601(s),
1460                _ => Self::parse_postgres(s),
1461            }
1462        }
1463    }
1464}
1465
1466impl FromStr for Interval {
1467    type Err = IntervalParseError;
1468
1469    fn from_str(s: &str) -> ParseResult<Self> {
1470        Self::parse_with_fields(s, None)
1471    }
1472}
1473
1474#[cfg(test)]
1475mod tests {
1476    use interval::test_utils::IntervalTestExt;
1477
1478    use super::*;
1479    use crate::types::ordered_float::OrderedFloat;
1480    use crate::util::panic::rw_catch_unwind;
1481
1482    #[test]
1483    fn test_parse() {
1484        let interval = "04:00:00".parse::<Interval>().unwrap();
1485        assert_eq!(interval, Interval::from_millis(4 * 3600 * 1000));
1486
1487        let interval = "1 year 2 months 3 days 00:00:01"
1488            .parse::<Interval>()
1489            .unwrap();
1490        assert_eq!(
1491            interval,
1492            Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1000)
1493        );
1494
1495        let interval = "1 year 2 months 3 days 00:00:00.001"
1496            .parse::<Interval>()
1497            .unwrap();
1498        assert_eq!(
1499            interval,
1500            Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1)
1501        );
1502
1503        let interval = "1 year 2 months 3 days 00:59:59.005"
1504            .parse::<Interval>()
1505            .unwrap();
1506        assert_eq!(
1507            interval,
1508            Interval::from_month(14)
1509                + Interval::from_days(3)
1510                + Interval::from_minutes(59)
1511                + Interval::from_millis(59000)
1512                + Interval::from_millis(5)
1513        );
1514
1515        let interval = "1 year 2 months 3 days 01".parse::<Interval>().unwrap();
1516        assert_eq!(
1517            interval,
1518            Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1000)
1519        );
1520
1521        let interval = "1 year 2 months 3 days 1:".parse::<Interval>().unwrap();
1522        assert_eq!(
1523            interval,
1524            Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(60)
1525        );
1526
1527        let interval = "1 year 2 months 3 days 1:2".parse::<Interval>().unwrap();
1528        assert_eq!(
1529            interval,
1530            Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(62)
1531        );
1532
1533        let interval = "1 year 2 months 3 days 1:2:".parse::<Interval>().unwrap();
1534        assert_eq!(
1535            interval,
1536            Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(62)
1537        );
1538
1539        let interval = "P1Y2M3DT0H5M0S".parse::<Interval>().unwrap();
1540        assert_eq!(
1541            interval,
1542            Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(5)
1543        );
1544    }
1545
1546    #[test]
1547    fn test_to_string() {
1548        assert_eq!(
1549            Interval::from_month_day_usec(-14, 3, (11 * 3600 + 45 * 60 + 14) * USECS_PER_SEC + 233)
1550                .to_string(),
1551            "-1 years -2 mons +3 days 11:45:14.000233"
1552        );
1553        assert_eq!(
1554            Interval::from_month_day_usec(-14, 3, 0).to_string(),
1555            "-1 years -2 mons +3 days"
1556        );
1557        assert_eq!(Interval::default().to_string(), "00:00:00");
1558        assert_eq!(
1559            Interval::from_month_day_usec(
1560                -14,
1561                3,
1562                -((11 * 3600 + 45 * 60 + 14) * USECS_PER_SEC + 233)
1563            )
1564            .to_string(),
1565            "-1 years -2 mons +3 days -11:45:14.000233"
1566        );
1567    }
1568
1569    #[test]
1570    fn test_exact_div() {
1571        let cases = [
1572            ((14, 6, 6), (14, 6, 6), Some(1)),
1573            ((0, 0, 0), (0, 0, 0), None),
1574            ((0, 0, 0), (1, 0, 0), Some(0)),
1575            ((1, 1, 1), (0, 0, 0), None),
1576            ((1, 1, 1), (1, 0, 0), None),
1577            ((10, 0, 0), (1, 0, 0), Some(10)),
1578            ((10, 0, 0), (4, 0, 0), None),
1579            ((0, 24, 0), (4, 0, 0), None),
1580            ((6, 8, 9), (3, 1, 3), None),
1581            ((6, 8, 12), (3, 4, 6), Some(2)),
1582        ];
1583
1584        for (lhs, rhs, expected) in cases {
1585            let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1586            let rhs = Interval::from_month_day_usec(rhs.0, rhs.1, rhs.2 as i64);
1587            let result = rw_catch_unwind(|| {
1588                let actual = lhs.exact_div(&rhs);
1589                assert_eq!(actual, expected);
1590            });
1591            if result.is_err() {
1592                println!("Failed on {}.exact_div({})", lhs, rhs);
1593                break;
1594            }
1595        }
1596    }
1597
1598    #[test]
1599    fn test_div_float() {
1600        let cases_int = [
1601            ((10, 8, 6), 2, Some((5, 4, 3))),
1602            ((1, 2, 33), 3, Some((0, 10, 57600000011i64))),
1603            ((1, 0, 11), 10, Some((0, 3, 1))),
1604            ((5, 6, 7), 0, None),
1605        ];
1606
1607        let cases_float = [
1608            ((10, 8, 6), 2.0f32, Some((5, 4, 3))),
1609            ((1, 2, 33), 3.0f32, Some((0, 10, 57600000011i64))),
1610            ((10, 15, 100), 2.5f32, Some((4, 6, 40))),
1611            ((5, 6, 7), 0.0f32, None),
1612        ];
1613
1614        for (lhs, rhs, expected) in cases_int {
1615            let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1616            let expected = expected.map(|x| Interval::from_month_day_usec(x.0, x.1, x.2));
1617
1618            let actual = lhs.div_float(rhs as i16);
1619            assert_eq!(actual, expected);
1620
1621            let actual = lhs.div_float(rhs);
1622            assert_eq!(actual, expected);
1623
1624            let actual = lhs.div_float(rhs as i64);
1625            assert_eq!(actual, expected);
1626        }
1627
1628        for (lhs, rhs, expected) in cases_float {
1629            let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1630            let expected = expected.map(|x| Interval::from_month_day_usec(x.0, x.1, x.2));
1631
1632            let actual = lhs.div_float(OrderedFloat::<f32>(rhs));
1633            assert_eq!(actual, expected);
1634
1635            let actual = lhs.div_float(OrderedFloat::<f64>(rhs as f64));
1636            assert_eq!(actual, expected);
1637        }
1638    }
1639
1640    #[test]
1641    fn test_serialize_deserialize() {
1642        let mut serializer = memcomparable::Serializer::new(vec![]);
1643        let a = Interval::from_month_day_usec(123, 456, 789);
1644        a.serialize(&mut serializer).unwrap();
1645        let buf = serializer.into_inner();
1646        let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1647        assert_eq!(Interval::deserialize(&mut deserializer).unwrap(), a);
1648    }
1649
1650    #[test]
1651    fn test_memcomparable() {
1652        let cases = [
1653            ((1, 2, 3), (4, 5, 6), Ordering::Less),
1654            ((0, 31, 0), (1, 0, 0), Ordering::Greater),
1655            ((1, 0, 0), (0, 0, USECS_PER_MONTH + 1), Ordering::Less),
1656            ((0, 1, 0), (0, 0, USECS_PER_DAY + 1), Ordering::Less),
1657            (
1658                (2, 3, 4),
1659                (1, 2, 4 + USECS_PER_DAY + USECS_PER_MONTH),
1660                Ordering::Equal,
1661            ),
1662        ];
1663
1664        for ((lhs_months, lhs_days, lhs_usecs), (rhs_months, rhs_days, rhs_usecs), order) in cases {
1665            let lhs = {
1666                let mut serializer = memcomparable::Serializer::new(vec![]);
1667                Interval::from_month_day_usec(lhs_months, lhs_days, lhs_usecs)
1668                    .serialize(&mut serializer)
1669                    .unwrap();
1670                serializer.into_inner()
1671            };
1672            let rhs = {
1673                let mut serializer = memcomparable::Serializer::new(vec![]);
1674                Interval::from_month_day_usec(rhs_months, rhs_days, rhs_usecs)
1675                    .serialize(&mut serializer)
1676                    .unwrap();
1677                serializer.into_inner()
1678            };
1679            assert_eq!(lhs.cmp(&rhs), order)
1680        }
1681    }
1682
1683    #[test]
1684    fn test_deserialize_justify() {
1685        let cases = [
1686            (
1687                (0, 0, USECS_PER_MONTH * 2 + USECS_PER_DAY * 3 + 4),
1688                Some((2, 3, 4i64, "2 mons 3 days 00:00:00.000004")),
1689            ),
1690            ((i32::MIN, i32::MIN, i64::MIN), None),
1691            ((i32::MAX, i32::MAX, i64::MAX), None),
1692            (
1693                (0, i32::MIN, i64::MIN),
1694                Some((
1695                    -75141187,
1696                    -29,
1697                    -14454775808,
1698                    "-6261765 years -7 mons -29 days -04:00:54.775808",
1699                )),
1700            ),
1701            (
1702                (i32::MIN, -60, i64::MAX),
1703                Some((
1704                    -2143925250,
1705                    -8,
1706                    -71945224193,
1707                    "-178660437 years -6 mons -8 days -19:59:05.224193",
1708                )),
1709            ),
1710        ];
1711        for ((lhs_months, lhs_days, lhs_usecs), rhs) in cases {
1712            let input = Interval::from_month_day_usec(lhs_months, lhs_days, lhs_usecs);
1713            let actual_deserialize = IntervalCmpValue::from(input).as_justified();
1714
1715            match rhs {
1716                None => {
1717                    assert_eq!(actual_deserialize, None);
1718                }
1719                Some((rhs_months, rhs_days, rhs_usecs, rhs_str)) => {
1720                    // We should test individual fields rather than using custom `Eq`
1721                    assert_eq!(actual_deserialize.unwrap().months(), rhs_months);
1722                    assert_eq!(actual_deserialize.unwrap().days(), rhs_days);
1723                    assert_eq!(actual_deserialize.unwrap().usecs(), rhs_usecs);
1724                    assert_eq!(actual_deserialize.unwrap().to_string(), rhs_str);
1725                }
1726            }
1727        }
1728
1729        // A false positive overflow that is buggy in PostgreSQL 15.2.
1730        let input = Interval::from_month_day_usec(i32::MIN, -30, 1);
1731        let actual_deserialize = IntervalCmpValue::from(input).as_justified();
1732        // It has a justified interval within range, and can be obtained by our deserialization.
1733        assert_eq!(actual_deserialize.unwrap().months(), i32::MIN);
1734        assert_eq!(actual_deserialize.unwrap().days(), -29);
1735        assert_eq!(actual_deserialize.unwrap().usecs(), -USECS_PER_DAY + 1);
1736    }
1737
1738    #[test]
1739    fn test_deserialize_alternate() {
1740        let cases = [
1741            (0, 0, USECS_PER_MONTH * 2 + USECS_PER_DAY * 3 + 4),
1742            (i32::MIN, i32::MIN, i64::MIN),
1743            (i32::MAX, i32::MAX, i64::MAX),
1744            (0, i32::MIN, i64::MIN),
1745            (i32::MIN, -60, i64::MAX),
1746        ];
1747        for (months, days, usecs) in cases {
1748            let input = Interval::from_month_day_usec(months, days, usecs);
1749
1750            let mut serializer = memcomparable::Serializer::new(vec![]);
1751            input.serialize(&mut serializer).unwrap();
1752            let buf = serializer.into_inner();
1753            let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1754            let actual = Interval::deserialize(&mut deserializer).unwrap();
1755
1756            // The Interval we get back can be a different one, but they should be equal.
1757            assert_eq!(actual, input);
1758        }
1759
1760        // Decoding invalid value
1761        let mut serializer = memcomparable::Serializer::new(vec![]);
1762        (i64::MAX, u64::MAX).serialize(&mut serializer).unwrap();
1763        let buf = serializer.into_inner();
1764        let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1765        assert!(Interval::deserialize(&mut deserializer).is_err());
1766
1767        let buf = i128::MIN.to_ne_bytes();
1768        rw_catch_unwind(|| {
1769            <Interval as crate::hash::HashKeyDe>::deserialize(&DataType::Interval, &mut &buf[..])
1770        })
1771        .unwrap_err();
1772    }
1773
1774    #[test]
1775    fn test_interval_estimate_size() {
1776        let interval = Interval::MIN;
1777        assert_eq!(interval.estimated_size(), 16);
1778    }
1779
1780    #[test]
1781    fn test_iso_8601() {
1782        let iso_8601_str = "P1Y2M3DT4H5M6.789123S";
1783        let lhs = Interval::from_month_day_usec(14, 3, 14706789123);
1784        let rhs = Interval::from_iso_8601(iso_8601_str).unwrap();
1785        assert_eq!(rhs.as_iso_8601().as_str(), iso_8601_str);
1786        assert_eq!(lhs, rhs);
1787    }
1788}