Skip to main content

mz_repr/adt/
datetime.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Date and time utilities.
11
12#![allow(missing_docs)]
13
14use std::collections::VecDeque;
15use std::fmt;
16use std::str::FromStr;
17
18use chrono::{NaiveDate, NaiveTime, Timelike};
19use mz_lowertest::MzReflect;
20use mz_persist_types::columnar::FixedSizeCodec;
21use mz_pgtz::timezone::Timezone;
22#[cfg(any(test, feature = "proptest"))]
23use proptest_derive::Arbitrary;
24use serde::{Deserialize, Serialize};
25
26use crate::adt::interval::Interval;
27
28/// Units of measurements associated with dates and times.
29///
30/// TODO(benesch): with enough thinking, this type could probably be merged with
31/// `DateTimeField`.
32#[derive(
33    Clone,
34    Copy,
35    Debug,
36    PartialOrd,
37    Ord,
38    PartialEq,
39    Eq,
40    Hash,
41    Serialize,
42    Deserialize,
43    MzReflect
44)]
45#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
46pub enum DateTimeUnits {
47    Epoch,
48    Millennium,
49    Century,
50    Decade,
51    Year,
52    Quarter,
53    Week,
54    Month,
55    Hour,
56    Day,
57    DayOfWeek,
58    DayOfYear,
59    IsoDayOfWeek,
60    IsoDayOfYear,
61    Minute,
62    Second,
63    Milliseconds,
64    Microseconds,
65    Timezone,
66    TimezoneHour,
67    TimezoneMinute,
68}
69
70impl fmt::Display for DateTimeUnits {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        match self {
73            Self::Epoch => f.write_str("epoch"),
74            Self::Millennium => f.write_str("millennium"),
75            Self::Century => f.write_str("century"),
76            Self::Decade => f.write_str("decade"),
77            Self::Year => f.write_str("year"),
78            Self::Quarter => f.write_str("quarter"),
79            Self::Week => f.write_str("week"),
80            Self::Month => f.write_str("month"),
81            Self::Hour => f.write_str("hour"),
82            Self::Day => f.write_str("day"),
83            Self::DayOfWeek => f.write_str("dow"),
84            Self::DayOfYear => f.write_str("doy"),
85            Self::IsoDayOfWeek => f.write_str("isodow"),
86            Self::IsoDayOfYear => f.write_str("isodoy"),
87            Self::Minute => f.write_str("minute"),
88            Self::Second => f.write_str("seconds"),
89            Self::Milliseconds => f.write_str("milliseconds"),
90            Self::Microseconds => f.write_str("microseconds"),
91            Self::Timezone => f.write_str("timezone"),
92            Self::TimezoneHour => f.write_str("timezone_hour"),
93            Self::TimezoneMinute => f.write_str("timezone_minute"),
94        }
95    }
96}
97
98impl FromStr for DateTimeUnits {
99    type Err = String;
100
101    fn from_str(s: &str) -> Result<Self, Self::Err> {
102        match s.to_lowercase().as_str() {
103            "epoch" => Ok(Self::Epoch),
104            "mil" | "millennia" | "millennium" | "millenniums" => Ok(Self::Millennium),
105            "c" | "cent" | "century" | "centuries" => Ok(Self::Century),
106            "dec" | "decs" | "decade" | "decades" => Ok(Self::Decade),
107            "y" | "year" | "years" | "yr" | "yrs" => Ok(Self::Year),
108            "qtr" | "quarter" => Ok(Self::Quarter),
109            "w" | "week" | "weeks" => Ok(Self::Week),
110            "d" | "day" | "days" => Ok(Self::Day),
111            "dow" => Ok(Self::DayOfWeek),
112            "doy" => Ok(Self::DayOfYear),
113            "isodow" => Ok(Self::IsoDayOfWeek),
114            "isodoy" => Ok(Self::IsoDayOfYear),
115            "h" | "hour" | "hours" | "hr" | "hrs" => Ok(Self::Hour),
116            "us" | "usec" | "usecs" | "useconds" | "microsecond" | "microseconds" => {
117                Ok(Self::Microseconds)
118            }
119            "m" | "min" | "mins" | "minute" | "minutes" => Ok(Self::Minute),
120            "mon" | "mons" | "month" | "months" => Ok(Self::Month),
121            "ms" | "msec" | "msecs" | "mseconds" | "millisecond" | "milliseconds" => {
122                Ok(Self::Milliseconds)
123            }
124            "s" | "sec" | "second" | "seconds" | "secs" => Ok(Self::Second),
125            "timezone" => Ok(Self::Timezone),
126            "timezone_h" | "timezone_hour" => Ok(Self::TimezoneHour),
127            "timezone_m" | "timezone_minute" => Ok(Self::TimezoneMinute),
128            _ => Err(format!("unknown units {}", s)),
129        }
130    }
131}
132
133/// Order of definition is important for PartialOrd and Ord to be derived correctly
134#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
135pub enum DateTimePart {
136    Microseconds,
137    Milliseconds,
138    Second,
139    Minute,
140    Hour,
141    Day,
142    Week,
143    Month,
144    Quarter,
145    Year,
146    Decade,
147    Century,
148    Millennium,
149}
150
151impl FromStr for DateTimePart {
152    type Err = String;
153
154    fn from_str(s: &str) -> Result<Self, Self::Err> {
155        let units: DateTimeUnits = s.parse()?;
156
157        match units {
158            DateTimeUnits::Microseconds => Ok(DateTimePart::Microseconds),
159            DateTimeUnits::Milliseconds => Ok(DateTimePart::Milliseconds),
160            DateTimeUnits::Second => Ok(DateTimePart::Second),
161            DateTimeUnits::Minute => Ok(DateTimePart::Minute),
162            DateTimeUnits::Hour => Ok(DateTimePart::Hour),
163            DateTimeUnits::Day => Ok(DateTimePart::Day),
164            DateTimeUnits::Week => Ok(DateTimePart::Week),
165            DateTimeUnits::Month => Ok(DateTimePart::Month),
166            DateTimeUnits::Quarter => Ok(DateTimePart::Quarter),
167            DateTimeUnits::Year => Ok(DateTimePart::Year),
168            DateTimeUnits::Decade => Ok(DateTimePart::Decade),
169            DateTimeUnits::Century => Ok(DateTimePart::Century),
170            DateTimeUnits::Millennium => Ok(DateTimePart::Millennium),
171            _ => Err(s.to_string()),
172        }
173    }
174}
175
176// Order of definition is important for PartialOrd and Ord to be derived correctly
177#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
178pub enum DateTimeField {
179    Microseconds,
180    Milliseconds,
181    Second,
182    Minute,
183    Hour,
184    Day,
185    Month,
186    Year,
187    Decade,
188    Century,
189    Millennium,
190}
191
192impl fmt::Display for DateTimeField {
193    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
194        f.write_str(match self {
195            DateTimeField::Millennium => "MILLENNIUM",
196            DateTimeField::Century => "CENTURY",
197            DateTimeField::Decade => "DECADE",
198            DateTimeField::Year => "YEAR",
199            DateTimeField::Month => "MONTH",
200            DateTimeField::Day => "DAY",
201            DateTimeField::Hour => "HOUR",
202            DateTimeField::Minute => "MINUTE",
203            DateTimeField::Second => "SECOND",
204            DateTimeField::Milliseconds => "MILLISECONDS",
205            DateTimeField::Microseconds => "MICROSECONDS",
206        })
207    }
208}
209
210/// Iterate over `DateTimeField`s in descending significance
211impl IntoIterator for DateTimeField {
212    type Item = DateTimeField;
213    type IntoIter = DateTimeFieldIterator;
214    fn into_iter(self) -> DateTimeFieldIterator {
215        DateTimeFieldIterator(Some(self))
216    }
217}
218
219impl FromStr for DateTimeField {
220    type Err = String;
221
222    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
223        match s.to_uppercase().as_ref() {
224            "MILLENNIUM" | "MILLENNIUMS" | "MILLENNIA" | "MIL" | "MILS" => Ok(Self::Millennium),
225            "CENTURY" | "CENTURIES" | "CENT" | "C" => Ok(Self::Century),
226            "DECADE" | "DECADES" | "DEC" | "DECS" => Ok(Self::Decade),
227            "YEAR" | "YEARS" | "YR" | "YRS" | "Y" => Ok(Self::Year),
228            "MONTH" | "MONTHS" | "MON" | "MONS" => Ok(Self::Month),
229            "DAY" | "DAYS" | "D" => Ok(Self::Day),
230            "HOUR" | "HOURS" | "HR" | "HRS" | "H" => Ok(Self::Hour),
231            "MINUTE" | "MINUTES" | "MIN" | "MINS" | "M" => Ok(Self::Minute),
232            "SECOND" | "SECONDS" | "SEC" | "SECS" | "S" => Ok(Self::Second),
233            "MILLISECOND" | "MILLISECONDS" | "MILLISECON" | "MILLISECONS" | "MSECOND"
234            | "MSECONDS" | "MSEC" | "MSECS" | "MS" => Ok(Self::Milliseconds),
235            "MICROSECOND" | "MICROSECONDS" | "MICROSECON" | "MICROSECONS" | "USECOND"
236            | "USECONDS" | "USEC" | "USECS" | "US" => Ok(Self::Microseconds),
237            _ => Err(format!("invalid DateTimeField: {}", s)),
238        }
239    }
240}
241
242impl DateTimeField {
243    /// Iterate the DateTimeField to the next value.
244    /// # Panics
245    /// - When called on Second
246    pub fn next_smallest(self) -> Self {
247        self.into_iter()
248            .next()
249            .unwrap_or_else(|| panic!("Cannot get smaller DateTimeField than {}", self))
250    }
251    /// Iterate the DateTimeField to the prior value.
252    /// # Panics
253    /// - When called on Year
254    pub fn next_largest(self) -> Self {
255        self.into_iter()
256            .next_back()
257            .unwrap_or_else(|| panic!("Cannot get larger DateTimeField than {}", self))
258    }
259
260    /// Returns the number of microseconds in a single unit of `field`.
261    ///
262    /// # Panics
263    ///
264    /// Panics if called on a non-time/day field.
265    pub fn micros_multiplier(self) -> i64 {
266        use DateTimeField::*;
267        match self {
268            Day | Hour | Minute | Second | Milliseconds | Microseconds => {}
269            _other => unreachable!("Do not call with a non-time/day field"),
270        }
271
272        Interval::convert_date_time_unit(self, Self::Microseconds, 1i64).unwrap()
273    }
274
275    /// Returns the number of months in a single unit of `field`.
276    ///
277    /// # Panics
278    ///
279    /// Panics if called on a duration field.
280    pub fn month_multiplier(self) -> i64 {
281        use DateTimeField::*;
282        match self {
283            Millennium | Century | Decade | Year => {}
284            _other => unreachable!("Do not call with a duration field"),
285        }
286
287        Interval::convert_date_time_unit(self, Self::Microseconds, 1i64).unwrap()
288    }
289}
290
291/// An iterator over DateTimeFields
292///
293/// Always starts with the value smaller than the current one.
294///
295/// ```
296/// use mz_repr::adt::datetime::DateTimeField::*;
297/// let mut itr = Hour.into_iter();
298/// assert_eq!(itr.next(), Some(Minute));
299/// assert_eq!(itr.next(), Some(Second));
300/// assert_eq!(itr.next(), Some(Milliseconds));
301/// assert_eq!(itr.next(), Some(Microseconds));
302/// assert_eq!(itr.next(), None);
303/// ```
304#[derive(Debug)]
305pub struct DateTimeFieldIterator(Option<DateTimeField>);
306
307/// Go through fields in descending significance order
308impl Iterator for DateTimeFieldIterator {
309    type Item = DateTimeField;
310    fn next(&mut self) -> Option<Self::Item> {
311        use DateTimeField::*;
312        self.0 = match self.0 {
313            Some(Millennium) => Some(Century),
314            Some(Century) => Some(Decade),
315            Some(Decade) => Some(Year),
316            Some(Year) => Some(Month),
317            Some(Month) => Some(Day),
318            Some(Day) => Some(Hour),
319            Some(Hour) => Some(Minute),
320            Some(Minute) => Some(Second),
321            Some(Second) => Some(Milliseconds),
322            Some(Milliseconds) => Some(Microseconds),
323            Some(Microseconds) => None,
324            None => None,
325        };
326        self.0.clone()
327    }
328}
329
330impl DoubleEndedIterator for DateTimeFieldIterator {
331    fn next_back(&mut self) -> Option<Self::Item> {
332        use DateTimeField::*;
333        self.0 = match self.0 {
334            Some(Millennium) => None,
335            Some(Century) => Some(Millennium),
336            Some(Decade) => Some(Century),
337            Some(Year) => Some(Decade),
338            Some(Month) => Some(Year),
339            Some(Day) => Some(Month),
340            Some(Hour) => Some(Day),
341            Some(Minute) => Some(Hour),
342            Some(Second) => Some(Minute),
343            Some(Milliseconds) => Some(Second),
344            Some(Microseconds) => Some(Milliseconds),
345            None => None,
346        };
347        self.0.clone()
348    }
349}
350
351/// Tracks a unit and a fraction from a parsed time-like string, e.g. INTERVAL
352/// '1.2' DAYS.
353#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
354pub struct DateTimeFieldValue {
355    /// Integer part of the value.
356    pub unit: i64,
357    /// Fractional part of value, padded to billions/has 9 digits of precision,
358    /// e.g. `.5` is represented as `500000000`.
359    pub fraction: i64,
360}
361
362impl Default for DateTimeFieldValue {
363    fn default() -> Self {
364        DateTimeFieldValue {
365            unit: 0,
366            fraction: 0,
367        }
368    }
369}
370
371impl DateTimeFieldValue {
372    /// Construct `DateTimeFieldValue { unit, fraction }`.
373    pub fn new(unit: i64, fraction: i64) -> Self {
374        DateTimeFieldValue { unit, fraction }
375    }
376
377    /// How much padding is added to the fractional portion to achieve a given precision.
378    /// e.g. with the current precision `.5` is represented as `500_000_000`.
379    const FRACTIONAL_DIGIT_PRECISION: i64 = 1_000_000_000;
380}
381
382/// All of the fields that can appear in a literal `DATE`, `TIME`, `TIMESTAMP`
383/// or `INTERVAL` string.
384#[derive(Debug, Clone, PartialEq, Eq, Hash)]
385pub struct ParsedDateTime {
386    pub millennium: Option<DateTimeFieldValue>,
387    pub century: Option<DateTimeFieldValue>,
388    pub decade: Option<DateTimeFieldValue>,
389    pub year: Option<DateTimeFieldValue>,
390    pub month: Option<DateTimeFieldValue>,
391    pub day: Option<DateTimeFieldValue>,
392    pub hour: Option<DateTimeFieldValue>,
393    pub minute: Option<DateTimeFieldValue>,
394    // second.fraction is equivalent to nanoseconds.
395    pub second: Option<DateTimeFieldValue>,
396    pub millisecond: Option<DateTimeFieldValue>,
397    pub microsecond: Option<DateTimeFieldValue>,
398    pub timezone_offset_second: Option<Timezone>,
399}
400
401impl Default for ParsedDateTime {
402    fn default() -> Self {
403        ParsedDateTime {
404            millennium: None,
405            century: None,
406            decade: None,
407            year: None,
408            month: None,
409            day: None,
410            hour: None,
411            minute: None,
412            second: None,
413            millisecond: None,
414            microsecond: None,
415            timezone_offset_second: None,
416        }
417    }
418}
419
420impl ParsedDateTime {
421    /// Compute an Interval from an ParsedDateTime.
422    ///
423    /// # Errors
424    /// - If any component overflows a parameter (i.e. i64).
425    pub fn compute_interval(&self) -> Result<Interval, String> {
426        use DateTimeField::*;
427        let mut months = 0i32;
428        let mut days = 0i32;
429        let mut micros = 0i64;
430
431        // Add all DateTimeFields, from Millennium to Microseconds.
432        self.add_field(Millennium, &mut months, &mut days, &mut micros)?;
433
434        for field in Millennium.into_iter().take_while(|f| *f >= Microseconds) {
435            self.add_field(field, &mut months, &mut days, &mut micros)?;
436        }
437
438        Ok(Interval::new(months, days, micros))
439    }
440    /// Adds the appropriate values from self's ParsedDateTime to `months`,
441    /// `days`, and `micros`. These fields are then appropriate to construct
442    /// std::time::Duration, once accounting for their sign.
443    ///
444    /// # Errors
445    /// - If any component overflows a parameter (i.e. i64).
446    fn add_field(
447        &self,
448        d: DateTimeField,
449        months: &mut i32,
450        days: &mut i32,
451        micros: &mut i64,
452    ) -> Result<(), String> {
453        use DateTimeField::*;
454        /// divide i by d rounding to the closest integer
455        fn div_and_round(i: i128, d: i64) -> Option<i64> {
456            let mut res = i / i128::from(d);
457            let round_digit = (i / (i128::from(d) / 10)) % 10;
458            if round_digit > 4 {
459                res += 1;
460            } else if round_digit < -4 {
461                res -= 1;
462            }
463            i64::try_from(res).ok()
464        }
465        match d {
466            Millennium | Century | Decade | Year => {
467                let (y, y_f) = match self.units_of(d) {
468                    Some(y) => (y.unit, y.fraction),
469                    None => return Ok(()),
470                };
471                // months += y.to_month()
472                *months = Interval::convert_date_time_unit(d, DateTimeField::Month, y)
473                    .and_then(|y_m| i32::try_from(y_m).ok())
474                    .and_then(|y_m| months.checked_add(y_m))
475                    .ok_or_else(|| {
476                        format!(
477                            "Overflows maximum months; cannot exceed {}/{} months",
478                            i32::MAX,
479                            i32::MIN,
480                        )
481                    })?;
482
483                // months += y_f.to_month() / DateTimeFieldValue::FRACTION_MULTIPLIER
484                *months = Interval::convert_date_time_unit(d, DateTimeField::Month, y_f)
485                    .and_then(|y_f_m| {
486                        y_f_m.checked_div(DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION)
487                    })
488                    .and_then(|y_f_m| i32::try_from(y_f_m).ok())
489                    .and_then(|y_f_m| months.checked_add(y_f_m))
490                    .ok_or_else(|| {
491                        format!(
492                            "Overflows maximum months; cannot exceed {}/{} months",
493                            i32::MAX,
494                            i32::MIN,
495                        )
496                    })?;
497                Ok(())
498            }
499            Month => {
500                let (m, m_f) = match self.units_of(Month) {
501                    Some(m) => (m.unit, m.fraction),
502                    None => return Ok(()),
503                };
504
505                // months += m
506                *months = i32::try_from(m)
507                    .ok()
508                    .and_then(|m_month| months.checked_add(m_month))
509                    .ok_or_else(|| {
510                        format!(
511                            "Overflows maximum months; cannot exceed {}/{} months",
512                            i32::MAX,
513                            i32::MIN,
514                        )
515                    })?;
516
517                let m_f_days = Interval::convert_date_time_unit(d, DateTimeField::Day, m_f)
518                    .ok_or_else(|| "Intermediate overflow in MONTH fraction".to_owned())?;
519                // days += m_f.to_day() / DateTimeFieldValue::FRACTION_MULTIPLIER
520                *days = m_f_days
521                    .checked_div(DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION)
522                    .and_then(|m_f_days| i32::try_from(m_f_days).ok())
523                    .and_then(|m_f_days| days.checked_add(m_f_days))
524                    .ok_or_else(|| {
525                        format!(
526                            "Overflows maximum seconds; cannot exceed {}/{} days",
527                            i32::MAX,
528                            i32::MIN,
529                        )
530                    })?;
531
532                // micros += (m_f.to_day() % DateTimeFieldValue::FRACTION_MULTIPLIER).to_micros() / DateTimeFieldValue::FRACTION_MULTIPLIER
533                *micros = i128::from(m_f_days)
534                    .checked_rem(DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION.into())
535                    .and_then(|m_f_us| {
536                        Interval::convert_date_time_unit(
537                            DateTimeField::Day,
538                            DateTimeField::Microseconds,
539                            m_f_us,
540                        )
541                    })
542                    .and_then(|m_f_us| {
543                        div_and_round(m_f_us, DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION)
544                    })
545                    .and_then(|m_f_us| micros.checked_add(m_f_us))
546                    .ok_or_else(|| {
547                        format!(
548                            "Overflows maximum microseconds; cannot exceed {}/{} microseconds",
549                            i64::MAX,
550                            i64::MIN
551                        )
552                    })?;
553
554                Ok(())
555            }
556            Day => {
557                let (t, t_f) = match self.units_of(d) {
558                    Some(t) => (t.unit, t.fraction),
559                    None => return Ok(()),
560                };
561
562                // days += t
563                *days = i32::try_from(t)
564                    .ok()
565                    .and_then(|t_day| days.checked_add(t_day))
566                    .ok_or_else(|| {
567                        format!(
568                            "Overflows maximum days; cannot exceed {}/{} days",
569                            i32::MAX,
570                            i32::MIN,
571                        )
572                    })?;
573
574                // micros += t_f.to_micros() / DateTimeFieldValue::FRACTION_MULTIPLIER
575                *micros = Interval::convert_date_time_unit(
576                    d,
577                    DateTimeField::Microseconds,
578                    i128::from(t_f),
579                )
580                .and_then(|t_f_us| {
581                    div_and_round(t_f_us, DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION)
582                })
583                .and_then(|t_f_us| micros.checked_add(t_f_us))
584                .ok_or_else(|| {
585                    format!(
586                        "Overflows maximum microseconds; cannot exceed {}/{} microseconds",
587                        i64::MAX,
588                        i64::MIN
589                    )
590                })?;
591
592                Ok(())
593            }
594            Hour | Minute | Second | Milliseconds | Microseconds => {
595                let (t, t_f) = match self.units_of(d) {
596                    Some(t) => (t.unit, t.fraction),
597                    None => return Ok(()),
598                };
599
600                // micros += t.to_micros()
601                *micros = Interval::convert_date_time_unit(d, DateTimeField::Microseconds, t)
602                    .and_then(|t_s| micros.checked_add(t_s))
603                    .ok_or_else(|| {
604                        format!(
605                            "Overflows maximum microseconds; cannot exceed {}/{} microseconds",
606                            i64::MAX,
607                            i64::MIN,
608                        )
609                    })?;
610
611                // micros += t_f.to_micros() / DateTimeFieldValue::FRACTION_MULTIPLIER
612                *micros = Interval::convert_date_time_unit(d, DateTimeField::Microseconds, t_f)
613                    .and_then(|t_f_ns| {
614                        div_and_round(
615                            t_f_ns.into(),
616                            DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION,
617                        )
618                    })
619                    .and_then(|t_f_ns| micros.checked_add(t_f_ns))
620                    .ok_or_else(|| {
621                        format!(
622                            "Overflows maximum microseconds; cannot exceed {}/{} microseconds",
623                            i64::MAX,
624                            i64::MIN,
625                        )
626                    })?;
627                Ok(())
628            }
629        }
630    }
631
632    /// Compute a chrono::NaiveDate from an ParsedDateTime.
633    ///
634    /// # Errors
635    /// - If year, month, or day overflows their respective parameter in
636    ///   [chrono::naive::date::NaiveDate::from_ymd_opt](https://docs.rs/chrono/0.4/chrono/naive/struct.NaiveDate.html#method.from_ymd_opt).
637    ///
638    /// Note: Postgres does not recognize Year 0, but in order to make
639    /// arithmetic work as expected, the Year 1 BC in a ParsedDateTime
640    /// is mapped to the Year 0 in a NaiveDate, and vice-versa.
641    pub fn compute_date(&self) -> Result<chrono::NaiveDate, String> {
642        match (self.year, self.month, self.day) {
643            (Some(year), Some(month), Some(day)) => {
644                // Adjust for BC years
645                let year = if year.unit < 0 {
646                    year.unit + 1
647                } else {
648                    year.unit
649                };
650                let p_err = |e, field| format!("{} in date is invalid: {}", field, e);
651                let year = year.try_into().map_err(|e| p_err(e, "Year"))?;
652                let month = month.unit.try_into().map_err(|e| p_err(e, "Month"))?;
653                let day = day.unit.try_into().map_err(|e| p_err(e, "Day"))?;
654                NaiveDate::from_ymd_opt(year, month, day)
655                    .ok_or_else(|| "invalid or out-of-range date".into())
656            }
657            (_, _, _) => Err("YEAR, MONTH, DAY are all required".into()),
658        }
659    }
660
661    /// Compute a chrono::NaiveDate from an ParsedDateTime.
662    ///
663    /// # Errors
664    /// - If hour, minute, or second (both `unit` and `fraction`) overflow `u32`.
665    pub fn compute_time(&self) -> Result<chrono::NaiveTime, String> {
666        let p_err = |e, field| format!("invalid {}: {}", field, e);
667        let hour = match self.hour {
668            Some(hour) => hour.unit.try_into().map_err(|e| p_err(e, "HOUR"))?,
669            None => 0,
670        };
671        let minute = match self.minute {
672            Some(minute) => minute.unit.try_into().map_err(|e| p_err(e, "MINUTE"))?,
673            None => 0,
674        };
675        let (second, nano) = match self.second {
676            Some(second) => {
677                let nano: u32 = second
678                    .fraction
679                    .try_into()
680                    .map_err(|e| p_err(e, "NANOSECOND"))?;
681                let second: u32 = second.unit.try_into().map_err(|e| p_err(e, "MINUTE"))?;
682                (second, nano)
683            }
684            None => (0, 0),
685        };
686        Ok(NaiveTime::from_hms_nano_opt(hour, minute, second, nano).unwrap())
687    }
688
689    /// Builds a ParsedDateTime from an interval string (`value`).
690    ///
691    /// # Arguments
692    ///
693    /// * `value` is a PostgreSQL-compatible interval string, e.g `INTERVAL 'value'`.
694    /// * `leading_time_precision` optionally identifies the leading time component
695    ///   HOUR | MINUTE to disambiguate {}:{} formatted intervals
696    /// * `ambiguous_resolver` identifies the DateTimeField of the final part
697    ///   if it's ambiguous, e.g. in `INTERVAL '1' MONTH` '1' is ambiguous as its
698    ///   DateTimeField, but MONTH resolves the ambiguity.
699    pub fn build_parsed_datetime_interval(
700        value: &str,
701        leading_time_precision: Option<DateTimeField>,
702        ambiguous_resolver: DateTimeField,
703    ) -> Result<ParsedDateTime, String> {
704        use DateTimeField::*;
705
706        let mut pdt = ParsedDateTime::default();
707        let mut value_parts = VecDeque::new();
708        let mut value_tokens = tokenize_time_str(value.trim())?;
709        let mut token_buffer = VecDeque::new();
710
711        while let Some(t) = value_tokens.pop_front() {
712            match t {
713                TimeStrToken::Delim => {
714                    if !token_buffer.is_empty() {
715                        value_parts.push_back(token_buffer.clone());
716                        token_buffer.clear();
717                    }
718                }
719                // Equivalent to trimming Colons from each leading element.
720                TimeStrToken::Colon if token_buffer.is_empty() => {}
721                _ => token_buffer.push_back(t),
722            }
723        }
724
725        if !token_buffer.is_empty() {
726            value_parts.push_back(token_buffer)
727        }
728
729        let mut annotated_parts = Vec::new();
730
731        while let Some(part) = value_parts.pop_front() {
732            let mut fmt = determine_format_w_datetimefield(part.clone(), leading_time_precision)?;
733            // If you cannot determine the format of this part, try to infer its
734            // format.
735            if fmt.is_none() {
736                fmt = match value_parts.pop_front() {
737                    Some(next_part) => {
738                        match determine_format_w_datetimefield(next_part.clone(), None)? {
739                            Some(TimePartFormat::SqlStandard(f)) => {
740                                match f {
741                                    // Do not capture this token because expression
742                                    // is going to fail.
743                                    Year | Month | Day => None,
744                                    // If following part is H:M:S, infer that this
745                                    // part is Day. Because this part can use a
746                                    // fraction, it should be parsed as PostgreSQL.
747                                    _ => {
748                                        // We can capture these annotated tokens
749                                        // because expressions are commutative.
750                                        annotated_parts.push(AnnotatedIntervalPart {
751                                            fmt: TimePartFormat::SqlStandard(f),
752                                            tokens: next_part.clone(),
753                                        });
754                                        Some(TimePartFormat::PostgreSql(Day))
755                                    }
756                                }
757                            }
758                            // None | Some(TimePartFormat::PostgreSQL(f))
759                            // If next_fmt is TimePartFormat::PostgreSQL, that
760                            // indicates that the following string was a TimeUnit,
761                            // e.g. `day`, and this is where those tokens get
762                            // consumed and propagated to their preceding numerical
763                            // value.
764                            next_fmt => next_fmt,
765                        }
766                    }
767                    // Allow resolution of final part using ambiguous_resolver.
768                    None => Some(TimePartFormat::PostgreSql(ambiguous_resolver)),
769                }
770            }
771            match fmt {
772                Some(fmt) => annotated_parts.push(AnnotatedIntervalPart {
773                    fmt,
774                    tokens: part.clone(),
775                }),
776                None => {
777                    return Err("Cannot determine format of all parts. Add \
778                        explicit time components, e.g. INTERVAL '1 day' or INTERVAL '1' DAY"
779                        .into());
780                }
781            }
782        }
783
784        for mut ap in annotated_parts {
785            match ap.fmt {
786                TimePartFormat::SqlStandard(f) => {
787                    fill_pdt_interval_sql(&mut ap.tokens, f, &mut pdt)?;
788                    pdt.check_interval_bounds(f)?;
789                }
790                TimePartFormat::PostgreSql(f) => fill_pdt_interval_pg(&mut ap.tokens, f, &mut pdt)?,
791            }
792
793            // Consume unused TimeUnits for PG compat.
794            while let Some(TimeStrToken::TimeUnit(_)) = ap.tokens.front() {
795                ap.tokens.pop_front();
796            }
797
798            if !ap.tokens.is_empty() {
799                return Err(format!(
800                    "have unprocessed tokens {}",
801                    itertools::join(ap.tokens, "").trim_end(),
802                ));
803            }
804        }
805
806        Ok(pdt)
807    }
808    /// Builds a ParsedDateTime from a TIMESTAMP string (`value`).
809    ///
810    /// # Arguments
811    ///
812    /// * `value` is a SQL-formatted TIMESTAMP string.
813    pub fn build_parsed_datetime_timestamp(
814        value: &str,
815        era: CalendarEra,
816    ) -> Result<ParsedDateTime, String> {
817        let mut pdt = ParsedDateTime::default();
818
819        let mut ts_actual = tokenize_time_str(value)?;
820
821        fill_pdt_date(&mut pdt, &mut ts_actual)?;
822
823        if let CalendarEra::BC = era {
824            pdt.year = pdt.year.map(|mut y| {
825                y.unit = -y.unit;
826                y
827            });
828        }
829
830        if let Some(TimeStrToken::DateTimeDelimiter) = ts_actual.front() {
831            ts_actual.pop_front();
832            ltrim_delim_or_colon(&mut ts_actual);
833        }
834
835        fill_pdt_time(&mut pdt, &mut ts_actual)?;
836        pdt.check_datelike_bounds()?;
837
838        if ts_actual.is_empty() {
839            Ok(pdt)
840        } else {
841            Err(format!(
842                "have unprocessed tokens {}",
843                itertools::join(ts_actual, "").trim_end(),
844            ))
845        }
846    }
847    /// Builds a ParsedDateTime from a TIME string (`value`).
848    ///
849    /// # Arguments
850    ///
851    /// * `value` is a SQL-formatted TIME string.
852    pub fn build_parsed_datetime_time(value: &str) -> Result<ParsedDateTime, String> {
853        let mut pdt = ParsedDateTime::default();
854
855        let mut time_actual = tokenize_time_str(value)?;
856        fill_pdt_time(&mut pdt, &mut time_actual)?;
857        pdt.check_datelike_bounds()?;
858
859        if time_actual.is_empty() {
860            Ok(pdt)
861        } else {
862            Err(format!(
863                "have unprocessed tokens {}",
864                itertools::join(time_actual, "").trim_end(),
865            ))
866        }
867    }
868
869    /// Write to the specified field of a ParsedDateTime iff it is currently set
870    /// to None; otherwise generate an error to propagate to the user.
871    pub fn write_field_iff_none(
872        &mut self,
873        f: DateTimeField,
874        u: Option<DateTimeFieldValue>,
875    ) -> Result<(), String> {
876        use DateTimeField::*;
877
878        if let Some(unwrapped_u) = &u {
879            match f {
880                Millennium if self.millennium.is_none() => {
881                    self.millennium = u;
882                }
883                Century if self.century.is_none() => {
884                    self.century = u;
885                }
886                Decade if self.decade.is_none() => {
887                    self.decade = u;
888                }
889                Year if self.year.is_none() => {
890                    self.year = u;
891                }
892                Month if self.month.is_none() => {
893                    self.month = u;
894                }
895                Day if self.day.is_none() => {
896                    self.day = u;
897                }
898                Hour if self.hour.is_none() => {
899                    self.hour = u;
900                }
901                Minute if self.minute.is_none() => {
902                    self.minute = u;
903                }
904                Second if self.second.is_none() => {
905                    if unwrapped_u.fraction != 0
906                        && (self.millisecond.is_some() || self.microsecond.is_some())
907                    {
908                        return Err(format!(
909                            "Cannot set {} or {} field if {} field has a fraction component",
910                            Milliseconds, Microseconds, f
911                        ));
912                    }
913                    self.second = u;
914                }
915                Milliseconds if self.millisecond.is_none() => {
916                    if self.seconds_has_fraction() {
917                        return Err(format!(
918                            "Cannot set {} or {} field if {} field has a fraction component",
919                            f, Microseconds, Second
920                        ));
921                    }
922                    self.millisecond = u;
923                }
924                Microseconds if self.microsecond.is_none() => {
925                    if self.seconds_has_fraction() {
926                        return Err(format!(
927                            "Cannot set {} or {} field if {} field has a fraction component",
928                            Milliseconds, f, Second
929                        ));
930                    }
931                    self.microsecond = u;
932                }
933                _ => return Err(format!("{} field set twice", f)),
934            }
935        }
936        Ok(())
937    }
938
939    fn seconds_has_fraction(&self) -> bool {
940        self.second.is_some() && self.second.as_ref().unwrap().fraction != 0
941    }
942
943    pub fn check_datelike_bounds(&mut self) -> Result<(), String> {
944        if let Some(year) = self.year {
945            // 1BC is not represented as year 0 at the parser level, only internally
946            if year.unit == 0 {
947                return Err("YEAR cannot be zero".to_string());
948            }
949        }
950        if let Some(month) = self.month {
951            if month.unit < 1 || month.unit > 12 {
952                return Err(format!("MONTH must be [1, 12], got {}", month.unit));
953            };
954        }
955        if let Some(day) = self.day {
956            if day.unit < 1 || day.unit > 31 {
957                return Err(format!("DAY must be [1, 31], got {}", day.unit));
958            };
959        }
960        if let Some(hour) = self.hour {
961            if hour.unit < 0 || hour.unit > 23 {
962                return Err(format!("HOUR must be [0, 23], got {}", hour.unit));
963            };
964        }
965        if let Some(minute) = self.minute {
966            if minute.unit < 0 || minute.unit > 59 {
967                return Err(format!("MINUTE must be [0, 59], got {}", minute.unit));
968            };
969        }
970
971        if let Some(second) = &mut self.second {
972            // Chrono supports leap seconds by moving them into nanos:
973            // https://docs.rs/chrono/0.4.19/chrono/naive/struct.NaiveTime.html#leap-second-handling
974            // See also Tom Lane saying that leap seconds are not well handled:
975            // https://www.postgresql.org/message-id/23016.1327976502@sss.pgh.pa.us
976            if second.unit == 60 {
977                second.unit = 59;
978                second.fraction = second.fraction.saturating_add(1_000_000_000);
979            }
980            if second.unit < 0 || second.unit > 60 {
981                return Err(format!("SECOND must be [0, 60], got {}", second.unit));
982            };
983            if second.fraction < 0 || second.fraction > 1_000_000_000 {
984                return Err(format!(
985                    "NANOSECOND must be [0, 1_000_000_000], got {}",
986                    second.fraction
987                ));
988            };
989        }
990
991        Ok(())
992    }
993    pub fn check_interval_bounds(&self, d: DateTimeField) -> Result<(), String> {
994        use DateTimeField::*;
995
996        match d {
997            Millennium | Century | Decade | Year | Month => {
998                if let Some(month) = self.month {
999                    if month.unit < -12 || month.unit > 12 {
1000                        return Err(format!("MONTH must be [-12, 12], got {}", month.unit));
1001                    };
1002                }
1003            }
1004            Hour | Minute | Second | Milliseconds | Microseconds => {
1005                if let Some(minute) = self.minute {
1006                    if minute.unit < -59 || minute.unit > 59 {
1007                        return Err(format!("MINUTE must be [-59, 59], got {}", minute.unit));
1008                    };
1009                }
1010
1011                let mut seconds = 0;
1012                let mut nanoseconds = 0;
1013
1014                if let Some(second) = self.second {
1015                    seconds += second.unit;
1016                    nanoseconds += second.fraction;
1017                }
1018
1019                if let Some(millisecond) = self.millisecond {
1020                    seconds += millisecond.unit / 1_000;
1021                    nanoseconds += (millisecond.unit % 1_000) * 1_000_000;
1022                    nanoseconds += (millisecond.fraction / 1_000) % 1_000_000_000;
1023                }
1024
1025                if let Some(microsecond) = self.microsecond {
1026                    seconds += microsecond.unit / 1_000_000;
1027                    nanoseconds += (microsecond.unit % 1_000_000) * 1_000;
1028                    nanoseconds += (microsecond.fraction / 1_000_000) % 1_000_000_000;
1029                }
1030
1031                if seconds < -60 || seconds > 60 {
1032                    return Err(format!("SECOND must be [-60, 60], got {}", seconds));
1033                };
1034                if nanoseconds < -1_000_000_000 || nanoseconds > 1_000_000_000 {
1035                    return Err(format!(
1036                        "NANOSECOND must be [-1_000_000_000, 1_000_000_000], got {}",
1037                        nanoseconds
1038                    ));
1039                };
1040            }
1041            Day => {}
1042        }
1043
1044        Ok(())
1045    }
1046
1047    pub fn clear_date(&mut self) {
1048        self.year = None;
1049        self.month = None;
1050        self.day = None;
1051    }
1052
1053    /// Retrieve any value that we parsed out of the literal string for the
1054    /// `field`.
1055    fn units_of(&self, field: DateTimeField) -> Option<DateTimeFieldValue> {
1056        match field {
1057            DateTimeField::Millennium => self.millennium,
1058            DateTimeField::Century => self.century,
1059            DateTimeField::Decade => self.decade,
1060            DateTimeField::Year => self.year,
1061            DateTimeField::Month => self.month,
1062            DateTimeField::Day => self.day,
1063            DateTimeField::Hour => self.hour,
1064            DateTimeField::Minute => self.minute,
1065            DateTimeField::Second => self.second,
1066            DateTimeField::Milliseconds => self.millisecond,
1067            DateTimeField::Microseconds => self.microsecond,
1068        }
1069    }
1070}
1071
1072/// Fills the year, month, and day fields of `pdt` using the `TimeStrToken`s in
1073/// `actual`.
1074///
1075/// # Args
1076///
1077/// - `pdt`: The ParsedDateTime to fill.
1078/// - `actual`: The queue of tokens representing the string you want use to fill
1079///   `pdt`'s fields.
1080fn fill_pdt_date(
1081    pdt: &mut ParsedDateTime,
1082    actual: &mut VecDeque<TimeStrToken>,
1083) -> Result<(), String> {
1084    use TimeStrToken::*;
1085
1086    // Check for one number that represents YYYYMMDDD.
1087    match actual.front() {
1088        Some(&Num(mut val, ref digits)) if 6 <= *digits && *digits <= 8 => {
1089            let unit = i64::try_from(val % 100)
1090                .expect("modulo between u64 and constant 100 should fit signed 64-bit integer");
1091            pdt.day = Some(DateTimeFieldValue::new(unit, 0));
1092            val /= 100;
1093
1094            let unit = i64::try_from(val % 100)
1095                .expect("modulo between u64 and constant 100 should fit signed 64-bit integer");
1096            pdt.month = Some(DateTimeFieldValue::new(unit, 0));
1097            val /= 100;
1098            // Handle 2 digit year case
1099            if *digits == 6 {
1100                if val < 70 {
1101                    val += 2000;
1102                } else {
1103                    val += 1900;
1104                }
1105            }
1106
1107            let unit = i64::try_from(val)
1108                .map_err(|_| "number should fit in signed 64-bit integer".to_string())?;
1109            pdt.year = Some(DateTimeFieldValue::new(unit, 0));
1110            actual.pop_front();
1111            // Trim remaining optional tokens, but never an immediately
1112            // following colon
1113            if let Some(Delim) = actual.front() {
1114                actual.pop_front();
1115                ltrim_delim_or_colon(actual);
1116            }
1117            return Ok(());
1118        }
1119        _ => (),
1120    }
1121
1122    let valid_formats = [
1123        [
1124            Num(0, 1), // year
1125            Dash,
1126            Num(0, 1), // month
1127            Dash,
1128            Num(0, 1), // day
1129        ],
1130        [
1131            Num(0, 1), // year
1132            Delim,
1133            Num(0, 1), // month
1134            Dash,
1135            Num(0, 1), // day
1136        ],
1137        [
1138            Num(0, 1), // year
1139            Delim,
1140            Num(0, 1), // month
1141            Delim,
1142            Num(0, 1), // day
1143        ],
1144    ];
1145
1146    let original_actual = actual.clone();
1147
1148    for expected in valid_formats {
1149        match fill_pdt_from_tokens(pdt, actual, &expected, DateTimeField::Year, 1) {
1150            Ok(()) => {
1151                return Ok(());
1152            }
1153            Err(_) => {
1154                actual.clone_from(&original_actual);
1155                pdt.clear_date();
1156            }
1157        }
1158    }
1159
1160    Err("does not match any format for date component".into())
1161}
1162
1163/// Fills the hour, minute, and second fields of `pdt` using the `TimeStrToken`s in
1164/// `actual`.
1165///
1166/// # Args
1167///
1168/// - `pdt`: The ParsedDateTime to fill.
1169/// - `actual`: The queue of tokens representing the string you want use to fill
1170///   `pdt`'s fields.
1171fn fill_pdt_time(
1172    pdt: &mut ParsedDateTime,
1173    actual: &mut VecDeque<TimeStrToken>,
1174) -> Result<(), String> {
1175    match determine_format_w_datetimefield(actual.clone(), None)? {
1176        Some(TimePartFormat::SqlStandard(leading_field)) => {
1177            let expected = expected_dur_like_tokens(leading_field)?;
1178
1179            fill_pdt_from_tokens(pdt, actual, expected, leading_field, 1)
1180        }
1181        _ => Ok(()),
1182    }
1183}
1184
1185/// Fills a ParsedDateTime's fields when encountering SQL standard-style interval
1186/// parts, e.g. `1-2` for Y-M `4:5:6.7` for H:M:S.NS.
1187///
1188/// Note that:
1189/// - SQL-standard style groups ({Y-M}{D}{H:M:S.NS}) require that no fields in
1190///   the group have been modified, and do not allow any fields to be modified
1191///   afterward.
1192/// - Single digits, e.g. `3` in `3 4:5:6.7` could be parsed as SQL standard
1193///   tokens, but end up being parsed as PostgreSQL-style tokens because of their
1194///   greater expressivity, in that they allow fractions, and otherwise-equivalence.
1195fn fill_pdt_interval_sql(
1196    actual: &mut VecDeque<TimeStrToken>,
1197    leading_field: DateTimeField,
1198    pdt: &mut ParsedDateTime,
1199) -> Result<(), String> {
1200    use DateTimeField::*;
1201
1202    // Ensure that no fields have been previously modified.
1203    match leading_field {
1204        Year | Month => {
1205            if pdt.year.is_some() || pdt.month.is_some() {
1206                return Err("YEAR or MONTH field set twice".into());
1207            }
1208        }
1209        Day => {
1210            if pdt.day.is_some() {
1211                return Err("DAY field set twice".into());
1212            }
1213        }
1214        Hour | Minute | Second => {
1215            if pdt.hour.is_some() || pdt.minute.is_some() || pdt.second.is_some() {
1216                return Err("HOUR, MINUTE, SECOND field set twice".into());
1217            }
1218        }
1219        Millennium | Century | Decade | Milliseconds | Microseconds => {
1220            return Err(format!(
1221                "Cannot specify {} field for SQL standard-style interval parts",
1222                leading_field
1223            ));
1224        }
1225    }
1226
1227    let expected = expected_sql_standard_interval_tokens(leading_field);
1228
1229    let sign = trim_and_return_sign(actual);
1230
1231    fill_pdt_from_tokens(pdt, actual, expected, leading_field, sign)?;
1232
1233    // Write default values to any unwritten member of the `leading_field`'s group.
1234    // This will ensure that those fields cannot be written to at a later time, which
1235    // is part of the SQL standard behavior for timelike components.
1236    match leading_field {
1237        Year | Month => {
1238            if pdt.year.is_none() {
1239                pdt.year = Some(DateTimeFieldValue::default());
1240            }
1241            if pdt.month.is_none() {
1242                pdt.month = Some(DateTimeFieldValue::default());
1243            }
1244        }
1245        Day => {
1246            if pdt.day.is_none() {
1247                pdt.day = Some(DateTimeFieldValue::default());
1248            }
1249        }
1250        Hour | Minute | Second => {
1251            if pdt.hour.is_none() {
1252                pdt.hour = Some(DateTimeFieldValue::default());
1253            }
1254            if pdt.minute.is_none() {
1255                pdt.minute = Some(DateTimeFieldValue::default());
1256            }
1257            if pdt.second.is_none() {
1258                pdt.second = Some(DateTimeFieldValue::default());
1259            }
1260        }
1261        Millennium | Century | Decade | Milliseconds | Microseconds => {
1262            return Err(format!(
1263                "Cannot specify {} field for SQL standard-style interval parts",
1264                leading_field
1265            ));
1266        }
1267    }
1268
1269    Ok(())
1270}
1271
1272/// Fills a ParsedDateTime's fields for a single PostgreSQL-style interval
1273/// parts, e.g. `1 month`. Invoke this function once for each PostgreSQL-style
1274/// interval part.
1275///
1276/// Note that:
1277/// - This function only meaningfully parses the numerical component of the
1278///   string, and relies on determining the DateTimeField component from
1279///   AnnotatedIntervalPart, passed in as `time_unit`.
1280/// - Only PostgreSQL-style parts can use fractional components in positions
1281///   other than seconds, e.g. `1.5 months`.
1282fn fill_pdt_interval_pg(
1283    actual: &mut VecDeque<TimeStrToken>,
1284    time_unit: DateTimeField,
1285    pdt: &mut ParsedDateTime,
1286) -> Result<(), String> {
1287    use TimeStrToken::*;
1288
1289    // We remove all spaces during tokenization, so TimeUnit only shows up if
1290    // there is no space between the number and the TimeUnit, e.g. `1y 2d 3h`, which
1291    // PostgreSQL allows.
1292    let expected = [Num(0, 1), Dot, Nanos(0), TimeUnit(DateTimeField::Year)];
1293
1294    let sign = trim_and_return_sign(actual);
1295
1296    fill_pdt_from_tokens(pdt, actual, &expected, time_unit, sign)?;
1297
1298    Ok(())
1299}
1300
1301/// Fills a ParsedDateTime's fields using the `actual` tokens, starting at `leading_field`
1302/// and descending to less significant DateTimeFields.
1303///
1304/// # Errors
1305/// - If `actual` doesn't match `expected`, modulo skippable TimeStrTokens.
1306/// - Setting a field in ParsedDateTime that has already been set.
1307///
1308/// # Panics
1309/// - Trying to advance to the next smallest DateTimeField if you're currently
1310///     at DateTimeField::Second.
1311fn fill_pdt_from_tokens<'a, E: IntoIterator<Item = &'a TimeStrToken>>(
1312    pdt: &mut ParsedDateTime,
1313    actual: &mut VecDeque<TimeStrToken>,
1314    expected: E,
1315    leading_field: DateTimeField,
1316    sign: i64,
1317) -> Result<(), String> {
1318    use TimeStrToken::*;
1319    let mut current_field = leading_field;
1320
1321    let mut i = 0u8;
1322
1323    let mut unit_buf: Option<DateTimeFieldValue> = None;
1324
1325    let mut expected = expected.into_iter().peekable();
1326
1327    while let (Some(atok), Some(etok)) = (actual.front(), expected.peek()) {
1328        match (atok, etok) {
1329            // The following forms of punctuation signal the end of a field and can
1330            // trigger a write.
1331            (Dash, Dash) | (Colon, Colon) => {
1332                pdt.write_field_iff_none(current_field, unit_buf)?;
1333                unit_buf = None;
1334                current_field = current_field.next_smallest();
1335            }
1336            (Delim, Delim) => {
1337                pdt.write_field_iff_none(current_field, unit_buf)?;
1338                unit_buf = None;
1339                current_field = current_field.next_smallest();
1340
1341                // Spaces require special processing to allow users to enter an
1342                // arbitrary number of delimiters wherever they're allowed. Note
1343                // that this does not include colons.
1344                actual.pop_front();
1345                expected.next();
1346                i += 1;
1347
1348                while let Some(Delim) = actual.front() {
1349                    actual.pop_front();
1350                }
1351
1352                continue;
1353            }
1354            (TimeUnit(f), TimeUnit(_)) => {
1355                if unit_buf.is_some() && *f != current_field {
1356                    return Err(format!(
1357                        "Invalid syntax at offset {}: provided TimeUnit({}) but expected TimeUnit({})",
1358                        i, f, current_field
1359                    ));
1360                }
1361            }
1362            // If we got a DateTimeUnits, attempt to convert it to a TimeUnit.
1363            (DateTimeUnit(u), TimeUnit(_)) => {
1364                let f = match u {
1365                    DateTimeUnits::Hour => DateTimeField::Hour,
1366                    DateTimeUnits::Minute => DateTimeField::Minute,
1367                    DateTimeUnits::Second => DateTimeField::Second,
1368                    DateTimeUnits::Milliseconds => DateTimeField::Milliseconds,
1369                    DateTimeUnits::Microseconds => DateTimeField::Microseconds,
1370                    _ => return Err(format!("unsupported unit {}", u)),
1371                };
1372                if unit_buf.is_some() && f != current_field {
1373                    return Err(format!(
1374                        "Invalid syntax at offset {}: provided DateTimeUnit({}) but expected TimeUnit({})",
1375                        u, f, current_field
1376                    ));
1377                }
1378            }
1379            (Dot, Dot) => {}
1380            (Num(val, _), Num(_, _)) => match unit_buf {
1381                Some(_) => {
1382                    return Err(
1383                        "Invalid syntax; parts must be separated by '-', ':', or ' '".to_string(),
1384                    );
1385                }
1386                None => {
1387                    // create signed copy of *val
1388                    let unit = i64::try_from(i128::from(*val) * i128::from(sign))
1389                        .map_err(|_| format!("Unable to parse value {val} as a number: number too large to fit in target type"))?;
1390                    unit_buf = Some(DateTimeFieldValue { unit, fraction: 0 });
1391                }
1392            },
1393            (Nanos(val), Nanos(_)) => match unit_buf {
1394                Some(ref mut u) => {
1395                    u.fraction = *val * sign;
1396                }
1397                None => {
1398                    unit_buf = Some(DateTimeFieldValue {
1399                        unit: 0,
1400                        fraction: *val * sign,
1401                    });
1402                }
1403            },
1404            (Num(n, _), Nanos(_)) => {
1405                // Create disposable copy of n.
1406                let mut nc = *n;
1407
1408                let mut width = 0;
1409                // Destructively count the number of digits in n.
1410                while nc != 0 {
1411                    nc /= 10;
1412                    width += 1;
1413                }
1414
1415                let mut n = *n;
1416
1417                // Nanoseconds have 9 digits of precision.
1418                let precision = 9;
1419
1420                if width > precision {
1421                    // Trim n to its 9 most significant digits.
1422                    n /= 10_u64.pow(width - precision);
1423                } else {
1424                    // Right-pad n with 0s.
1425                    n *= 10_u64.pow(precision - width);
1426                }
1427
1428                // create signed copy of n
1429                let sn  = i64::try_from(i128::from(n) * i128::from(sign))
1430                    .map_err(|_| format!("Unable to parse value {n} as a number: number too large to fit in target type"))?;
1431
1432                match unit_buf {
1433                    Some(ref mut u) => {
1434                        u.fraction = sn;
1435                    }
1436                    None => {
1437                        unit_buf = Some(DateTimeFieldValue {
1438                            unit: 0,
1439                            fraction: sn,
1440                        });
1441                    }
1442                }
1443            }
1444            // Allow skipping expected spaces (Delim), numbers, dots, and nanoseconds.
1445            (_, Num(_, _)) | (_, Dot) | (_, Nanos(_)) | (_, Delim) => {
1446                expected.next();
1447                continue;
1448            }
1449            (provided, expected) => {
1450                return Err(format!(
1451                    "Invalid syntax at offset {i}: provided {provided:?} but expected {expected:?}",
1452                ));
1453            }
1454        }
1455        i += 1;
1456        actual.pop_front();
1457        expected.next();
1458    }
1459
1460    ltrim_delim_or_colon(actual);
1461
1462    pdt.write_field_iff_none(current_field, unit_buf)?;
1463
1464    Ok(())
1465}
1466
1467/// Interval strings can be presented in one of two formats:
1468/// - SQL Standard, e.g. `1-2 3 4:5:6.7`
1469/// - PostgreSQL, e.g. `1 year 2 months 3 days`
1470/// TimePartFormat indicates which type of parsing to use and encodes a
1471/// DateTimeField, which indicates "where" you should begin parsing the
1472/// associated tokens w/r/t their respective syntax.
1473#[derive(Debug, Eq, PartialEq, Clone)]
1474enum TimePartFormat {
1475    SqlStandard(DateTimeField),
1476    PostgreSql(DateTimeField),
1477}
1478
1479/// AnnotatedIntervalPart contains the tokens to be parsed, as well as the format
1480/// to parse them.
1481#[derive(Debug, Eq, PartialEq, Clone)]
1482struct AnnotatedIntervalPart {
1483    pub tokens: VecDeque<TimeStrToken>,
1484    pub fmt: TimePartFormat,
1485}
1486
1487/// Determines the format of the interval part (uses None to identify an
1488/// indeterminant/ambiguous format). This is necessary because the interval
1489/// string format is not LL(1); we instead parse as few tokens as possible to
1490/// generate the string's semantics.
1491///
1492/// Note that `toks` should _not_ contain space
1493fn determine_format_w_datetimefield(
1494    mut toks: VecDeque<TimeStrToken>,
1495    leading_time_precision: Option<DateTimeField>,
1496) -> Result<Option<TimePartFormat>, String> {
1497    use DateTimeField::*;
1498    use TimePartFormat::*;
1499    use TimeStrToken::*;
1500
1501    trim_and_return_sign(&mut toks);
1502
1503    if let Some(Num(_, _)) = toks.front() {
1504        toks.pop_front();
1505    }
1506
1507    match toks.pop_front() {
1508        // Implies {?}{?}{?}, ambiguous case.
1509        None | Some(Delim) => Ok(None),
1510        Some(Dot) => {
1511            match toks.front() {
1512                Some(Num(_, _)) | Some(Nanos(_)) => {
1513                    toks.pop_front();
1514                }
1515                _ => {}
1516            }
1517            match toks.pop_front() {
1518                // Implies {Num.NumTimeUnit}
1519                Some(TimeUnit(f)) => Ok(Some(PostgreSql(f))),
1520                // Implies {?}{?}{?}, ambiguous case.
1521                _ => Ok(None),
1522            }
1523        }
1524        // Implies {Y-...}{}{}
1525        Some(Dash) => Ok(Some(SqlStandard(Year))),
1526        // Implies {}{}{?:...}
1527        Some(Colon) => {
1528            if let Some(Num(_, _)) = toks.front() {
1529                toks.pop_front();
1530            }
1531
1532            match toks.pop_front() {
1533                // Implies {H:M:?...}
1534                Some(Colon) | Some(Delim) => Ok(Some(SqlStandard(Hour))),
1535                // Implies {M:S.NS}
1536                Some(Dot) => Ok(Some(SqlStandard(Minute))),
1537                // Implies {a:b}. We default to {H:M}, and the leading
1538                // precision can be specified explicitly
1539                None => Ok(leading_time_precision
1540                    .map(SqlStandard)
1541                    .or(Some(SqlStandard(Hour)))),
1542                _ => Err("Cannot determine format of all parts".into()),
1543            }
1544        }
1545        // Implies {Num}?{TimeUnit}
1546        Some(TimeUnit(f)) => Ok(Some(PostgreSql(f))),
1547        Some(DateTimeUnit(DateTimeUnits::Hour)) => Ok(Some(PostgreSql(Hour))),
1548        Some(DateTimeUnit(DateTimeUnits::Minute)) => Ok(Some(PostgreSql(Minute))),
1549        Some(DateTimeUnit(DateTimeUnits::Second)) => Ok(Some(PostgreSql(Second))),
1550        Some(DateTimeUnit(DateTimeUnits::Milliseconds)) => Ok(Some(PostgreSql(Milliseconds))),
1551        Some(DateTimeUnit(DateTimeUnits::Microseconds)) => Ok(Some(PostgreSql(Microseconds))),
1552        Some(DateTimeUnit(_)) => Ok(None),
1553        _ => Err("Cannot determine format of all parts".into()),
1554    }
1555}
1556
1557/// Get the expected TimeStrTokens to parse SQL Standard time-like
1558/// DateTimeFields, i.e. HOUR, MINUTE, SECOND. This is used for INTERVAL,
1559/// TIMESTAMP, and TIME.
1560///
1561/// # Errors
1562/// - If `from` is YEAR, MONTH, or DAY.
1563fn expected_dur_like_tokens(from: DateTimeField) -> Result<&'static [TimeStrToken], String> {
1564    use DateTimeField::*;
1565    use TimeStrToken::*;
1566
1567    const ALL_TOKS: [TimeStrToken; 7] = [
1568        Num(0, 1), // hour
1569        Colon,
1570        Num(0, 1), // minute
1571        Colon,
1572        Num(0, 1), // second
1573        Dot,
1574        Nanos(0), // Nanos
1575    ];
1576    let start = match from {
1577        Hour => 0,
1578        Minute => 2,
1579        Second => 4,
1580        _ => {
1581            return Err(format!(
1582                "expected_dur_like_tokens can only be called with HOUR, MINUTE, SECOND; got {}",
1583                from
1584            ));
1585        }
1586    };
1587
1588    Ok(&ALL_TOKS[start..ALL_TOKS.len()])
1589}
1590
1591/// Get the expected TimeStrTokens to parse TimePartFormat::SqlStandard parts,
1592/// starting from some `DateTimeField`. Delim tokens are never actually included
1593/// in the output, but are illustrative of what the expected input of SQL
1594/// Standard interval values looks like.
1595fn expected_sql_standard_interval_tokens(from: DateTimeField) -> &'static [TimeStrToken] {
1596    use DateTimeField::*;
1597    use TimeStrToken::*;
1598
1599    const ALL_TOKS: [TimeStrToken; 6] = [
1600        Num(0, 1), // year
1601        Dash,
1602        Num(0, 1), // month
1603        Delim,
1604        Num(0, 1), // day
1605        Delim,
1606    ];
1607
1608    let (start, end) = match from {
1609        Year => (0, 4),
1610        Month => (2, 4),
1611        Day => (4, 6),
1612        _ => {
1613            return expected_dur_like_tokens(from)
1614                .expect("input to expected_dur_like_tokens shown to be valid");
1615        }
1616    };
1617
1618    &ALL_TOKS[start..end]
1619}
1620
1621fn trim_and_return_sign(z: &mut VecDeque<TimeStrToken>) -> i64 {
1622    use TimeStrToken::*;
1623
1624    match z.front() {
1625        Some(Dash) => {
1626            z.pop_front();
1627            -1
1628        }
1629        Some(Plus) => {
1630            z.pop_front();
1631            1
1632        }
1633        _ => 1,
1634    }
1635}
1636
1637/// PostgreSQL treats out-of-place colons as errant punctuation marks, and
1638/// trims them.
1639fn ltrim_delim_or_colon(z: &mut VecDeque<TimeStrToken>) {
1640    while Some(&TimeStrToken::Colon) == z.front() || Some(&TimeStrToken::Delim) == z.front() {
1641        z.pop_front();
1642    }
1643}
1644
1645/// TimeStrToken represents valid tokens in time-like strings,
1646/// i.e those used in INTERVAL, TIMESTAMP/TZ, DATE, and TIME.
1647#[derive(Debug, Clone, PartialEq, Eq)]
1648pub(crate) enum TimeStrToken {
1649    Dash,
1650    Colon,
1651    Dot,
1652    Plus,
1653    // Holds the parsed number and the number of digits in the original string
1654    Num(u64, usize),
1655    Nanos(i64),
1656    // Tokenized version of a DateTimeField string e.g. 'YEAR'
1657    TimeUnit(DateTimeField),
1658    // Fallback if TimeUnit isn't parseable.
1659    DateTimeUnit(DateTimeUnits),
1660    // Used to support ISO-formatted timestamps.
1661    DateTimeDelimiter,
1662    // Space arbitrary non-enum punctuation (e.g. !), or leading/trailing
1663    // colons.
1664    Delim,
1665}
1666
1667impl std::fmt::Display for TimeStrToken {
1668    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1669        use TimeStrToken::*;
1670        match self {
1671            Dash => write!(f, "-"),
1672            Colon => write!(f, ":"),
1673            Dot => write!(f, "."),
1674            Plus => write!(f, "+"),
1675            Num(i, digits) => write!(f, "{:01$}", i, digits - 1),
1676            Nanos(i) => write!(f, "{}", i),
1677            TimeUnit(d) => write!(f, "{:?}", d),
1678            DateTimeUnit(u) => write!(f, "{}", u),
1679            DateTimeDelimiter => write!(f, "T"),
1680            Delim => write!(f, " "),
1681        }
1682    }
1683}
1684
1685/// Convert a string from a time-like datatype (INTERVAL, TIMESTAMP/TZ, DATE, and TIME)
1686/// into `Vec<TimeStrToken>`.
1687///
1688/// # Warning
1689/// - Any sequence of numeric characters following a decimal that exceeds 9 characters
1690///   gets truncated to 9 characters, e.g. `0.1234567899` is truncated to `0.123456789`.
1691///
1692/// # Errors
1693/// - Any sequence of alphabetic characters cannot be cast into a DateTimeField.
1694/// - Any sequence of numeric characters cannot be cast into an i64.
1695/// - Any non-alpha numeric character cannot be cast into a TimeStrToken, e.g. `%`.
1696pub(crate) fn tokenize_time_str(value: &str) -> Result<VecDeque<TimeStrToken>, String> {
1697    let mut toks = VecDeque::new();
1698    let mut num_buf = String::with_capacity(4);
1699    let mut char_buf = String::with_capacity(7);
1700    fn parse_num(n: &str, idx: usize) -> Result<TimeStrToken, String> {
1701        Ok(TimeStrToken::Num(
1702            n.parse().map_err(|e| {
1703                format!("Unable to parse value as a number at index {}: {}", idx, e)
1704            })?,
1705            n.len(),
1706        ))
1707    }
1708    fn maybe_tokenize_num_buf(
1709        n: &mut String,
1710        i: usize,
1711        is_frac: &mut bool,
1712        t: &mut VecDeque<TimeStrToken>,
1713    ) -> Result<(), String> {
1714        if !n.is_empty() {
1715            if *is_frac {
1716                // Fractions only support 9 places of precision.
1717                n.truncate(9);
1718                let len = u32::try_from(n.len()).expect("length known to fit in a u32");
1719                let raw: i64 = n
1720                    .parse()
1721                    .map_err(|e| format!("couldn't parse fraction {}: {}", n, e))?;
1722                let multiplicand = 1_000_000_000 / 10_i64.pow(len);
1723                t.push_back(TimeStrToken::Nanos(raw * multiplicand));
1724                n.clear();
1725            } else {
1726                t.push_back(parse_num(n, i)?);
1727                n.clear();
1728            }
1729        }
1730        *is_frac = false;
1731        Ok(())
1732    }
1733    fn maybe_tokenize_char_buf(
1734        c: &mut String,
1735        t: &mut VecDeque<TimeStrToken>,
1736    ) -> Result<(), String> {
1737        if !c.is_empty() {
1738            // Supports ISO-formatted datetime strings.
1739            if c == "T" || c == "t" {
1740                t.push_back(TimeStrToken::DateTimeDelimiter);
1741            } else {
1742                match c.to_uppercase().parse() {
1743                    Ok(u) => t.push_back(TimeStrToken::TimeUnit(u)),
1744                    Err(_) => t.push_back(TimeStrToken::DateTimeUnit(c.parse()?)),
1745                }
1746            }
1747            c.clear();
1748        }
1749        Ok(())
1750    }
1751    let mut next_num_is_frac = false;
1752    for (i, chr) in value.chars().enumerate() {
1753        if !num_buf.is_empty() && !char_buf.is_empty() {
1754            return Err("Could not tokenize".into());
1755        }
1756        match chr {
1757            '+' => {
1758                maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1759                maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1760                toks.push_back(TimeStrToken::Plus);
1761            }
1762            '-' => {
1763                maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1764                maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1765                toks.push_back(TimeStrToken::Dash);
1766            }
1767            ':' => {
1768                maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1769                maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1770                toks.push_back(TimeStrToken::Colon);
1771            }
1772            '.' => {
1773                maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1774                maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1775                toks.push_back(TimeStrToken::Dot);
1776                next_num_is_frac = true;
1777            }
1778            chr if chr.is_digit(10) => {
1779                maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1780                num_buf.push(chr);
1781            }
1782            chr if chr.is_ascii_alphabetic() => {
1783                maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1784                char_buf.push(chr);
1785            }
1786            chr if chr.is_ascii_whitespace() || chr.is_ascii_punctuation() => {
1787                maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1788                maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1789                toks.push_back(TimeStrToken::Delim);
1790            }
1791            _ => {
1792                return Err(format!(
1793                    "Invalid character at offset {} in {}: {:?}",
1794                    i, value, chr
1795                ));
1796            }
1797        }
1798    }
1799
1800    maybe_tokenize_num_buf(&mut num_buf, value.len(), &mut next_num_is_frac, &mut toks)?;
1801    maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1802
1803    ltrim_delim_or_colon(&mut toks);
1804
1805    Ok(toks)
1806}
1807
1808#[derive(Debug, PartialEq, Eq)]
1809pub enum CalendarEra {
1810    BC,
1811    AD,
1812}
1813
1814/// Takes a 'date timezone' 'date time timezone' string and splits it into 'date
1815/// {time}' and 'timezone' components then checks for a 'CalenderEra' defaulting
1816/// to 'AD'.
1817pub(crate) fn split_timestamp_string(value: &str) -> (&str, &str, CalendarEra) {
1818    // First we need to see if the string contains " +" or " -" because
1819    // timestamps can come in a format YYYY-MM-DD {+|-}<tz> (where the timezone
1820    // string can have colons)
1821    let cut = value.find(" +").or_else(|| value.find(" -"));
1822
1823    if let Some(cut) = cut {
1824        let (datetime, timezone) = value.split_at(cut);
1825
1826        let (timezone, era) = strip_era_from_timezone(timezone);
1827
1828        return (datetime.trim(), timezone.trim(), era);
1829    }
1830
1831    // If we have a hh:mm:dd component, we need to go past that to see if we can
1832    // find a tz
1833    let colon = value.find(':');
1834
1835    if let Some(colon) = colon {
1836        let substring = value.get(colon..);
1837        if let Some(substring) = substring {
1838            let tz = substring
1839                .find(|c: char| (c == '-') || (c == '+') || (c == ' ') || c.is_ascii_alphabetic());
1840
1841            if let Some(tz) = tz {
1842                let (datetime, timezone) = value.split_at(colon + tz);
1843
1844                let (timezone, era) = strip_era_from_timezone(timezone);
1845
1846                return (datetime.trim(), timezone.trim(), era);
1847            }
1848        }
1849
1850        (value.trim(), "", CalendarEra::AD)
1851    } else {
1852        // We don't have a time, so the only formats available are YYY-mm-dd<tz>
1853        // or YYYY-MM-dd <tz> Numeric offset timezones need to be separated from
1854        // the ymd by a space.
1855        let cut = value.find(|c: char| c.is_ascii_alphabetic());
1856
1857        if let Some(cut) = cut {
1858            let (datetime, timezone) = value.split_at(cut);
1859
1860            let (timezone, era) = strip_era_from_timezone(timezone);
1861
1862            return (datetime.trim(), timezone.trim(), era);
1863        }
1864
1865        (value.trim(), "", CalendarEra::AD)
1866    }
1867}
1868
1869// We support three era formats:
1870//  1. "<timestamp><separator><timezone> <era>"
1871//  2. "<timestamp> <era>"
1872//  3. "<timestamp><era>"
1873//
1874// NB(ptravers): pg supports more formats than noted above.
1875fn strip_era_from_timezone(timezone: &str) -> (&str, CalendarEra) {
1876    use CalendarEra::{AD, BC};
1877    let timezone = timezone.trim();
1878    let timezone_upper = timezone.to_uppercase();
1879
1880    // Covers cases 1 and 2.
1881    if timezone.len() < 3 {
1882        return match (
1883            timezone_upper.strip_suffix("BC"),
1884            timezone_upper.strip_suffix("AD"),
1885        ) {
1886            (Some(_), None) => ("", BC),
1887            (None, Some(_)) => ("", AD),
1888            // NB(ptravers): we expect this to fail when we go to check
1889            // the timezone is valid in the next step.
1890            _ => (timezone, AD),
1891        };
1892    }
1893
1894    // Covers case 3.
1895    //
1896    // Safety: upper case and lower case chars for a, b, c, d, and \s
1897    // are all 1 byte so suffix is always of length 3 bytes.
1898    match (
1899        timezone_upper.strip_suffix(" BC"),
1900        timezone_upper.strip_suffix(" AD"),
1901    ) {
1902        (Some(_), None) => (&timezone[..timezone.len() - 3], BC),
1903        (None, Some(_)) => (&timezone[..timezone.len() - 3], AD),
1904        _ => (timezone, AD),
1905    }
1906}
1907
1908/// An encoded packed variant of [`NaiveTime`].
1909///
1910/// We uphold the invariant that [`PackedNaiveTime`] sorts the same as
1911/// [`NaiveTime`].
1912#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
1913pub struct PackedNaiveTime([u8; Self::SIZE]);
1914
1915impl FixedSizeCodec<NaiveTime> for PackedNaiveTime {
1916    const SIZE: usize = 8;
1917
1918    fn as_bytes(&self) -> &[u8] {
1919        &self.0
1920    }
1921
1922    fn from_bytes(slice: &[u8]) -> Result<Self, String> {
1923        let buf: [u8; Self::SIZE] = slice.try_into().map_err(|_| {
1924            format!(
1925                "size for PackedNaiveTime is {} bytes, got {}",
1926                Self::SIZE,
1927                slice.len()
1928            )
1929        })?;
1930        Ok(PackedNaiveTime(buf))
1931    }
1932
1933    #[inline]
1934    fn from_value(value: NaiveTime) -> Self {
1935        let secs = value.num_seconds_from_midnight();
1936        let nano = value.nanosecond();
1937
1938        let mut buf = [0u8; Self::SIZE];
1939
1940        (buf[..4]).copy_from_slice(&secs.to_be_bytes());
1941        (buf[4..]).copy_from_slice(&nano.to_be_bytes());
1942
1943        PackedNaiveTime(buf)
1944    }
1945
1946    #[inline]
1947    fn into_value(self) -> NaiveTime {
1948        let mut secs = [0u8; 4];
1949        secs.copy_from_slice(&self.0[..4]);
1950        let secs = u32::from_be_bytes(secs);
1951
1952        let mut nano = [0u8; 4];
1953        nano.copy_from_slice(&self.0[4..]);
1954        let nano = u32::from_be_bytes(nano);
1955
1956        NaiveTime::from_num_seconds_from_midnight_opt(secs, nano)
1957            .expect("NaiveTime roundtrips with PackedNaiveTime")
1958    }
1959}
1960
1961#[cfg(test)]
1962mod tests {
1963    use itertools::Itertools;
1964    use proptest::{prop_assert_eq, proptest};
1965
1966    use crate::scalar::add_arb_duration;
1967
1968    use super::*;
1969
1970    #[mz_ore::test]
1971    fn iterate_datetimefield() {
1972        use DateTimeField::*;
1973        assert_eq!(
1974            Millennium.into_iter().take(10).collect::<Vec<_>>(),
1975            vec![
1976                Century,
1977                Decade,
1978                Year,
1979                Month,
1980                Day,
1981                Hour,
1982                Minute,
1983                Second,
1984                Milliseconds,
1985                Microseconds
1986            ]
1987        )
1988    }
1989
1990    #[mz_ore::test]
1991    fn test_expected_dur_like_tokens() {
1992        use DateTimeField::*;
1993        use TimeStrToken::*;
1994        assert_eq!(
1995            expected_sql_standard_interval_tokens(Hour),
1996            vec![Num(0, 1), Colon, Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
1997        );
1998        assert_eq!(
1999            expected_sql_standard_interval_tokens(Minute),
2000            vec![Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2001        );
2002        assert_eq!(
2003            expected_sql_standard_interval_tokens(Second),
2004            vec![Num(0, 1), Dot, Nanos(0)]
2005        );
2006    }
2007
2008    #[mz_ore::test]
2009    fn test_expected_sql_standard_interval_tokens() {
2010        use DateTimeField::*;
2011        use TimeStrToken::*;
2012        assert_eq!(
2013            expected_sql_standard_interval_tokens(Year),
2014            vec![Num(0, 1), Dash, Num(0, 1), Delim]
2015        );
2016
2017        assert_eq!(
2018            expected_sql_standard_interval_tokens(Day),
2019            vec![Num(0, 1), Delim]
2020        );
2021        assert_eq!(
2022            expected_sql_standard_interval_tokens(Hour),
2023            vec![Num(0, 1), Colon, Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2024        );
2025    }
2026    #[mz_ore::test]
2027    fn test_trim_and_return_sign() {
2028        let test_cases = [
2029            ("-2", -1, "2"),
2030            ("3", 1, "3"),
2031            ("+5", 1, "5"),
2032            ("-", -1, ""),
2033            ("-YEAR", -1, "YEAR"),
2034            ("YEAR", 1, "YEAR"),
2035        ];
2036
2037        for test in test_cases.iter() {
2038            let mut s = tokenize_time_str(test.0).unwrap();
2039
2040            assert_eq!(trim_and_return_sign(&mut s), test.1);
2041            assert_eq!(s.front(), tokenize_time_str(test.2).unwrap().front());
2042        }
2043    }
2044    #[mz_ore::test]
2045    fn test_determine_format_w_datetimefield() {
2046        use DateTimeField::*;
2047        use TimePartFormat::*;
2048
2049        let test_cases = [
2050            ("1-2 3", Some(SqlStandard(Year))),
2051            ("4:5", Some(SqlStandard(Hour))),
2052            ("4:5.6", Some(SqlStandard(Minute))),
2053            ("-4:5.6", Some(SqlStandard(Minute))),
2054            ("+4:5.6", Some(SqlStandard(Minute))),
2055            ("year", Some(PostgreSql(Year))),
2056            ("4year", Some(PostgreSql(Year))),
2057            ("-4year", Some(PostgreSql(Year))),
2058            ("5", None),
2059            ("5.6", None),
2060            ("3 4:5:6.7", None),
2061        ];
2062
2063        for test in test_cases.iter() {
2064            let s = tokenize_time_str(test.0).unwrap();
2065
2066            match (
2067                determine_format_w_datetimefield(s, None).unwrap(),
2068                test.1.as_ref(),
2069            ) {
2070                (Some(a), Some(b)) => {
2071                    if a != *b {
2072                        panic!(
2073                            "determine_format_w_datetimefield_and_time returned {:?}, expected {:?}",
2074                            a, b,
2075                        )
2076                    }
2077                }
2078                (None, None) => {}
2079                (x, y) => panic!(
2080                    "determine_format_w_datetimefield_and_time returned {:?}, expected {:?}",
2081                    x, y,
2082                ),
2083            }
2084        }
2085    }
2086    #[mz_ore::test]
2087    fn test_determine_format_w_datetimefield_and_leading_time() {
2088        use DateTimeField::*;
2089        use TimePartFormat::*;
2090
2091        assert_eq!(
2092            determine_format_w_datetimefield(tokenize_time_str("4:5").unwrap(), None,).unwrap(),
2093            Some(SqlStandard(Hour))
2094        );
2095        assert_eq!(
2096            determine_format_w_datetimefield(
2097                tokenize_time_str("4:5").unwrap(),
2098                Some(DateTimeField::Minute),
2099            )
2100            .unwrap(),
2101            Some(SqlStandard(Minute))
2102        );
2103        assert_eq!(
2104            determine_format_w_datetimefield(
2105                tokenize_time_str("4:5").unwrap(),
2106                Some(DateTimeField::Hour),
2107            )
2108            .unwrap(),
2109            Some(SqlStandard(Hour))
2110        );
2111    }
2112    #[mz_ore::test]
2113    fn test_determine_format_w_datetimefield_error() {
2114        let test_cases = [
2115            ("1+2", "Cannot determine format of all parts"),
2116            ("1:2+3", "Cannot determine format of all parts"),
2117            ("1:1YEAR2", "Cannot determine format of all parts"),
2118        ];
2119
2120        for test in test_cases.iter() {
2121            let s = tokenize_time_str(test.0).unwrap();
2122            match determine_format_w_datetimefield(s, None) {
2123                Err(e) => assert_eq!(e.to_string(), test.1),
2124                Ok(f) => panic!(
2125                    "Test passed when expected to fail: {}, generated {:?}",
2126                    test.0, f
2127                ),
2128            };
2129        }
2130    }
2131
2132    #[mz_ore::test]
2133    fn test_fill_pdt_from_tokens() {
2134        use DateTimeField::*;
2135        let test_cases = [
2136            (
2137                ParsedDateTime {
2138                    year: Some(DateTimeFieldValue::new(1, 0)),
2139                    month: Some(DateTimeFieldValue::new(2, 0)),
2140                    day: Some(DateTimeFieldValue::new(3, 0)),
2141                    hour: Some(DateTimeFieldValue::new(4, 0)),
2142                    minute: Some(DateTimeFieldValue::new(5, 0)),
2143                    second: Some(DateTimeFieldValue::new(6, 0)),
2144                    ..Default::default()
2145                },
2146                "1 2 3 4 5 6",
2147                "0 0 0 0 0 0",
2148                Year,
2149                1,
2150            ),
2151            (
2152                ParsedDateTime {
2153                    day: Some(DateTimeFieldValue::new(4, 0)),
2154                    hour: Some(DateTimeFieldValue::new(5, 0)),
2155                    minute: Some(DateTimeFieldValue::new(6, 0)),
2156                    ..Default::default()
2157                },
2158                "4 5 6",
2159                "0 0 0",
2160                Day,
2161                1,
2162            ),
2163            (
2164                ParsedDateTime {
2165                    day: Some(DateTimeFieldValue::new(-4, 0)),
2166                    hour: Some(DateTimeFieldValue::new(-5, 0)),
2167                    minute: Some(DateTimeFieldValue::new(-6, 0)),
2168                    ..Default::default()
2169                },
2170                "4 5 6",
2171                "0 0 0",
2172                Day,
2173                -1,
2174            ),
2175            // Mixed delimiter parsing
2176            (
2177                ParsedDateTime {
2178                    year: Some(DateTimeFieldValue::new(1, 0)),
2179                    month: Some(DateTimeFieldValue::new(2, 0)),
2180                    day: Some(DateTimeFieldValue::new(3, 0)),
2181                    hour: Some(DateTimeFieldValue::new(4, 0)),
2182                    minute: Some(DateTimeFieldValue::new(5, 0)),
2183                    second: Some(DateTimeFieldValue::new(6, 0)),
2184                    ..Default::default()
2185                },
2186                "1-2:3-4 5 6",
2187                "0-0:0-0 0 0",
2188                Year,
2189                1,
2190            ),
2191            // Skip an element at the end
2192            (
2193                ParsedDateTime {
2194                    year: Some(DateTimeFieldValue::new(1, 0)),
2195                    month: Some(DateTimeFieldValue::new(2, 0)),
2196                    day: Some(DateTimeFieldValue::new(3, 0)),
2197                    hour: Some(DateTimeFieldValue::new(5, 0)),
2198                    minute: Some(DateTimeFieldValue::new(6, 0)),
2199                    ..Default::default()
2200                },
2201                "1 2 3 5 6",
2202                "0 0 0 0 0 0",
2203                Year,
2204                1,
2205            ),
2206            // Skip an element w/ non-space parsing
2207            (
2208                ParsedDateTime {
2209                    year: Some(DateTimeFieldValue::new(1, 0)),
2210                    month: Some(DateTimeFieldValue::new(2, 0)),
2211                    day: Some(DateTimeFieldValue::new(3, 0)),
2212                    minute: Some(DateTimeFieldValue::new(5, 0)),
2213                    second: Some(DateTimeFieldValue::new(6, 0)),
2214                    ..Default::default()
2215                },
2216                "1-2:3- 5 6",
2217                "0-0:0-0 0 0",
2218                Year,
2219                1,
2220            ),
2221            // Get Nanos from tokenizer
2222            (
2223                ParsedDateTime {
2224                    year: Some(DateTimeFieldValue::new(1, 0)),
2225                    month: Some(DateTimeFieldValue::new(2, 0)),
2226                    day: Some(DateTimeFieldValue::new(3, 0)),
2227                    hour: Some(DateTimeFieldValue::new(4, 0)),
2228                    minute: Some(DateTimeFieldValue::new(5, 0)),
2229                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2230                    ..Default::default()
2231                },
2232                "1-2:3-4 5 6.7",
2233                "0-0:0-0 0 0.0",
2234                Year,
2235                1,
2236            ),
2237            // Proper fraction/nano conversion anywhere
2238            (
2239                ParsedDateTime {
2240                    year: Some(DateTimeFieldValue::new(1, 200_000_000)),
2241                    ..Default::default()
2242                },
2243                "1.2",
2244                "0.0",
2245                Year,
2246                1,
2247            ),
2248            (
2249                ParsedDateTime {
2250                    minute: Some(DateTimeFieldValue::new(1, 200_000_000)),
2251                    ..Default::default()
2252                },
2253                "1.2",
2254                "0.0",
2255                Minute,
2256                1,
2257            ),
2258            // Parse TimeUnit
2259            (
2260                ParsedDateTime {
2261                    month: Some(DateTimeFieldValue::new(3, 0)),
2262                    ..Default::default()
2263                },
2264                "3MONTHS",
2265                "0YEAR",
2266                Month,
2267                1,
2268            ),
2269            (
2270                ParsedDateTime {
2271                    month: Some(DateTimeFieldValue::new(1, 0)),
2272                    day: Some(DateTimeFieldValue::new(2, 0)),
2273                    hour: Some(DateTimeFieldValue::new(3, 0)),
2274                    ..Default::default()
2275                },
2276                "1MONTHS 2DAYS 3HOURS",
2277                "0YEAR 0YEAR 0YEAR",
2278                Month,
2279                1,
2280            ),
2281            (
2282                ParsedDateTime {
2283                    month: Some(DateTimeFieldValue::new(1, 0)),
2284                    day: Some(DateTimeFieldValue::new(2, 0)),
2285                    ..Default::default()
2286                },
2287                "1MONTHS-2",
2288                "0YEAR-0",
2289                Month,
2290                1,
2291            ),
2292        ];
2293        for test in test_cases.iter() {
2294            let mut pdt = ParsedDateTime::default();
2295            let mut actual = tokenize_time_str(test.1).unwrap();
2296            let expected = tokenize_time_str(test.2).unwrap();
2297
2298            fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.3, test.4).unwrap();
2299
2300            assert_eq!(pdt, test.0);
2301        }
2302    }
2303
2304    #[mz_ore::test]
2305    fn test_fill_pdt_from_tokens_errors() {
2306        use DateTimeField::*;
2307        let test_cases = [
2308            // Mismatched syntax
2309            (
2310                "1 2 3",
2311                "0-0 0",
2312                Year,
2313                1,
2314                "Invalid syntax at offset 1: provided Delim but expected Dash",
2315            ),
2316        ];
2317        for test in test_cases.iter() {
2318            let mut pdt = ParsedDateTime::default();
2319            let mut actual = tokenize_time_str(test.0).unwrap();
2320            let expected = tokenize_time_str(test.1).unwrap();
2321
2322            match fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.2, test.3) {
2323                Err(e) => assert_eq!(e.to_string(), test.4),
2324                Ok(_) => panic!("Test passed when expected to fail, generated {:?}", pdt),
2325            };
2326        }
2327    }
2328    #[mz_ore::test]
2329    #[should_panic(expected = "Cannot get smaller DateTimeField than MICROSECONDS")]
2330    fn test_fill_pdt_from_tokens_panic() {
2331        use DateTimeField::*;
2332        let test_cases = [
2333            // Mismatched syntax
2334            ("1 2", "0 0", Microseconds, 1),
2335        ];
2336        for test in test_cases.iter() {
2337            let mut pdt = ParsedDateTime::default();
2338            let mut actual = tokenize_time_str(test.0).unwrap();
2339            let expected = tokenize_time_str(test.1).unwrap();
2340
2341            if fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.2, test.3).is_ok() {
2342                panic!(
2343                    "test_fill_pdt_from_tokens_panic should have panicked. input {}\nformat {}\
2344                     \nDateTimeField {}\nGenerated ParsedDateTime {:?}",
2345                    test.0, test.1, test.2, pdt
2346                );
2347            };
2348        }
2349    }
2350
2351    #[mz_ore::test]
2352    fn test_fill_pdt_interval_pg() {
2353        use DateTimeField::*;
2354        let test_cases = [
2355            (
2356                ParsedDateTime {
2357                    year: Some(DateTimeFieldValue::new(2, 0)),
2358                    ..Default::default()
2359                },
2360                "2",
2361                Year,
2362            ),
2363            (
2364                ParsedDateTime {
2365                    month: Some(DateTimeFieldValue::new(2, 300_000_000)),
2366                    ..Default::default()
2367                },
2368                "2.3",
2369                Month,
2370            ),
2371            (
2372                ParsedDateTime {
2373                    day: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2374                    ..Default::default()
2375                },
2376                "-2.3",
2377                Day,
2378            ),
2379            (
2380                ParsedDateTime {
2381                    hour: Some(DateTimeFieldValue::new(2, 0)),
2382                    ..Default::default()
2383                },
2384                "2",
2385                Hour,
2386            ),
2387            (
2388                ParsedDateTime {
2389                    minute: Some(DateTimeFieldValue::new(2, 300_000_000)),
2390                    ..Default::default()
2391                },
2392                "2.3",
2393                Minute,
2394            ),
2395            (
2396                ParsedDateTime {
2397                    second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2398                    ..Default::default()
2399                },
2400                "-2.3",
2401                Second,
2402            ),
2403            (
2404                ParsedDateTime {
2405                    year: Some(DateTimeFieldValue::new(2, 0)),
2406                    ..Default::default()
2407                },
2408                "2year",
2409                Year,
2410            ),
2411            (
2412                ParsedDateTime {
2413                    month: Some(DateTimeFieldValue::new(2, 300_000_000)),
2414                    ..Default::default()
2415                },
2416                "2.3month",
2417                Month,
2418            ),
2419            (
2420                ParsedDateTime {
2421                    day: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2422                    ..Default::default()
2423                },
2424                "-2.3day",
2425                Day,
2426            ),
2427            (
2428                ParsedDateTime {
2429                    hour: Some(DateTimeFieldValue::new(2, 0)),
2430                    ..Default::default()
2431                },
2432                "2hour",
2433                Hour,
2434            ),
2435            (
2436                ParsedDateTime {
2437                    minute: Some(DateTimeFieldValue::new(2, 300_000_000)),
2438                    ..Default::default()
2439                },
2440                "2.3minute",
2441                Minute,
2442            ),
2443            (
2444                ParsedDateTime {
2445                    second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2446                    ..Default::default()
2447                },
2448                "-2.3second",
2449                Second,
2450            ),
2451            (
2452                ParsedDateTime {
2453                    second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2454                    ..Default::default()
2455                },
2456                ":::::::::-2.3second",
2457                Second,
2458            ),
2459            (
2460                ParsedDateTime {
2461                    second: Some(DateTimeFieldValue::new(2, 300_000_000)),
2462                    ..Default::default()
2463                },
2464                ":::::::::+2.3second",
2465                Second,
2466            ),
2467            (
2468                ParsedDateTime {
2469                    millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
2470                    ..Default::default()
2471                },
2472                "1.2milliseconds",
2473                Milliseconds,
2474            ),
2475            (
2476                ParsedDateTime {
2477                    microsecond: Some(DateTimeFieldValue::new(2, 300_000_000)),
2478                    ..Default::default()
2479                },
2480                "2.3microseconds",
2481                Microseconds,
2482            ),
2483            (
2484                ParsedDateTime {
2485                    millennium: Some(DateTimeFieldValue::new(4, 500_000_000)),
2486                    ..Default::default()
2487                },
2488                "4.5millennium",
2489                Millennium,
2490            ),
2491            (
2492                ParsedDateTime {
2493                    century: Some(DateTimeFieldValue::new(6, 700_000_000)),
2494                    ..Default::default()
2495                },
2496                "6.7century",
2497                Century,
2498            ),
2499            (
2500                ParsedDateTime {
2501                    decade: Some(DateTimeFieldValue::new(8, 900_000_000)),
2502                    ..Default::default()
2503                },
2504                "8.9decade",
2505                Decade,
2506            ),
2507        ];
2508        for test in test_cases.iter() {
2509            let mut pdt = ParsedDateTime::default();
2510            let mut actual = tokenize_time_str(test.1).unwrap();
2511            fill_pdt_interval_pg(&mut actual, test.2, &mut pdt).unwrap();
2512
2513            assert_eq!(pdt, test.0);
2514        }
2515    }
2516
2517    #[mz_ore::test]
2518    fn fill_pdt_interval_pg_errors() {
2519        use DateTimeField::*;
2520        let test_cases = [
2521            // Invalid syntax
2522            (
2523                "1.2.",
2524                Month,
2525                "Invalid syntax at offset 3: provided Dot but expected TimeUnit(Year)",
2526            ),
2527            // Running into this error means that determine_format_w_datetimefield
2528            // failed.
2529            (
2530                "1YEAR",
2531                Month,
2532                "Invalid syntax at offset 1: provided TimeUnit(YEAR) but expected TimeUnit(MONTH)",
2533            ),
2534        ];
2535        for test in test_cases.iter() {
2536            let mut pdt = ParsedDateTime::default();
2537            let mut actual = tokenize_time_str(test.0).unwrap();
2538            match fill_pdt_interval_pg(&mut actual, test.1, &mut pdt) {
2539                Err(e) => assert_eq!(e.to_string(), test.2),
2540                Ok(_) => panic!(
2541                    "Test passed when expected to fail, generated {:?}, expected error {}",
2542                    pdt, test.2,
2543                ),
2544            };
2545        }
2546    }
2547
2548    #[mz_ore::test]
2549    fn test_fill_pdt_interval_sql() {
2550        use DateTimeField::*;
2551        let test_cases = [
2552            (
2553                ParsedDateTime {
2554                    year: Some(DateTimeFieldValue::new(1, 0)),
2555                    month: Some(DateTimeFieldValue::new(2, 0)),
2556                    ..Default::default()
2557                },
2558                "1-2",
2559                Year,
2560            ),
2561            (
2562                ParsedDateTime {
2563                    hour: Some(DateTimeFieldValue::new(1, 0)),
2564                    minute: Some(DateTimeFieldValue::new(2, 0)),
2565                    second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2566                    ..Default::default()
2567                },
2568                "1:2:3.4",
2569                Hour,
2570            ),
2571            (
2572                ParsedDateTime {
2573                    hour: Some(DateTimeFieldValue::new(1, 0)),
2574                    minute: Some(DateTimeFieldValue::new(0, 0)),
2575                    second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2576                    ..Default::default()
2577                },
2578                "1::3.4",
2579                Hour,
2580            ),
2581            (
2582                ParsedDateTime {
2583                    hour: Some(DateTimeFieldValue::new(1, 0)),
2584                    minute: Some(DateTimeFieldValue::new(0, 0)),
2585                    second: Some(DateTimeFieldValue::new(0, 400_000_000)),
2586                    ..Default::default()
2587                },
2588                "1::.4",
2589                Hour,
2590            ),
2591            (
2592                ParsedDateTime {
2593                    hour: Some(DateTimeFieldValue::new(0, 0)),
2594                    minute: Some(DateTimeFieldValue::new(0, 0)),
2595                    second: Some(DateTimeFieldValue::new(0, 400_000_000)),
2596                    ..Default::default()
2597                },
2598                ".4",
2599                Second,
2600            ),
2601            (
2602                ParsedDateTime {
2603                    hour: Some(DateTimeFieldValue::new(0, 0)),
2604                    minute: Some(DateTimeFieldValue::new(1, 0)),
2605                    second: Some(DateTimeFieldValue::new(2, 300_000_000)),
2606                    ..Default::default()
2607                },
2608                "1:2.3",
2609                Minute,
2610            ),
2611            (
2612                ParsedDateTime {
2613                    year: Some(DateTimeFieldValue::new(-1, 0)),
2614                    month: Some(DateTimeFieldValue::new(-2, 0)),
2615                    ..Default::default()
2616                },
2617                "-1-2",
2618                Year,
2619            ),
2620            (
2621                ParsedDateTime {
2622                    hour: Some(DateTimeFieldValue::new(-1, 0)),
2623                    minute: Some(DateTimeFieldValue::new(-2, 0)),
2624                    second: Some(DateTimeFieldValue::new(-3, -400_000_000)),
2625                    ..Default::default()
2626                },
2627                "-1:2:3.4",
2628                Hour,
2629            ),
2630            (
2631                ParsedDateTime {
2632                    year: Some(DateTimeFieldValue::new(1, 0)),
2633                    month: Some(DateTimeFieldValue::new(2, 0)),
2634                    ..Default::default()
2635                },
2636                "+1-2",
2637                Year,
2638            ),
2639            (
2640                ParsedDateTime {
2641                    hour: Some(DateTimeFieldValue::new(1, 0)),
2642                    minute: Some(DateTimeFieldValue::new(2, 0)),
2643                    second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2644                    ..Default::default()
2645                },
2646                "+1:2:3.4",
2647                Hour,
2648            ),
2649            (
2650                ParsedDateTime {
2651                    year: Some(DateTimeFieldValue::new(-1, 0)),
2652                    month: Some(DateTimeFieldValue::new(-2, 0)),
2653                    ..Default::default()
2654                },
2655                "::::::-1-2",
2656                Year,
2657            ),
2658            (
2659                ParsedDateTime {
2660                    hour: Some(DateTimeFieldValue::new(-1, 0)),
2661                    minute: Some(DateTimeFieldValue::new(-2, 0)),
2662                    second: Some(DateTimeFieldValue::new(-3, -400_000_000)),
2663                    ..Default::default()
2664                },
2665                ":::::::-1:2:3.4",
2666                Hour,
2667            ),
2668        ];
2669        for test in test_cases.iter() {
2670            let mut pdt = ParsedDateTime::default();
2671            let mut actual = tokenize_time_str(test.1).unwrap();
2672            fill_pdt_interval_sql(&mut actual, test.2, &mut pdt).unwrap();
2673
2674            assert_eq!(pdt, test.0);
2675        }
2676    }
2677
2678    #[mz_ore::test]
2679    fn test_fill_pdt_interval_sql_errors() {
2680        use DateTimeField::*;
2681        let test_cases = [
2682            // Invalid syntax
2683            (
2684                "1.2",
2685                Year,
2686                "Invalid syntax at offset 1: provided Dot but expected Dash",
2687            ),
2688            (
2689                "1-2:3.4",
2690                Minute,
2691                "Invalid syntax at offset 1: provided Dash but expected Colon",
2692            ),
2693            (
2694                "1YEAR",
2695                Year,
2696                "Invalid syntax at offset 1: provided TimeUnit(Year) but expected Dash",
2697            ),
2698        ];
2699        for test in test_cases.iter() {
2700            let mut pdt = ParsedDateTime::default();
2701            let mut actual = tokenize_time_str(test.0).unwrap();
2702            match fill_pdt_interval_sql(&mut actual, test.1, &mut pdt) {
2703                Err(e) => assert_eq!(e.to_string(), test.2),
2704                Ok(_) => panic!("Test passed when expected to fail, generated {:?}", pdt),
2705            };
2706        }
2707    }
2708
2709    #[mz_ore::test]
2710    fn test_build_parsed_datetime_time() {
2711        run_test_build_parsed_datetime_time(
2712            "3:4:5.6",
2713            ParsedDateTime {
2714                hour: Some(DateTimeFieldValue::new(3, 0)),
2715                minute: Some(DateTimeFieldValue::new(4, 0)),
2716                second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2717                ..Default::default()
2718            },
2719        );
2720        run_test_build_parsed_datetime_time(
2721            "3:4",
2722            ParsedDateTime {
2723                hour: Some(DateTimeFieldValue::new(3, 0)),
2724                minute: Some(DateTimeFieldValue::new(4, 0)),
2725                ..Default::default()
2726            },
2727        );
2728        run_test_build_parsed_datetime_time(
2729            "3:4.5",
2730            ParsedDateTime {
2731                minute: Some(DateTimeFieldValue::new(3, 0)),
2732                second: Some(DateTimeFieldValue::new(4, 500_000_000)),
2733                ..Default::default()
2734            },
2735        );
2736        run_test_build_parsed_datetime_time(
2737            "0::4.5",
2738            ParsedDateTime {
2739                hour: Some(DateTimeFieldValue::new(0, 0)),
2740                second: Some(DateTimeFieldValue::new(4, 500_000_000)),
2741                ..Default::default()
2742            },
2743        );
2744        run_test_build_parsed_datetime_time(
2745            "0::.5",
2746            ParsedDateTime {
2747                hour: Some(DateTimeFieldValue::new(0, 0)),
2748                second: Some(DateTimeFieldValue::new(0, 500_000_000)),
2749                ..Default::default()
2750            },
2751        );
2752
2753        fn run_test_build_parsed_datetime_time(test: &str, res: ParsedDateTime) {
2754            assert_eq!(
2755                ParsedDateTime::build_parsed_datetime_time(test).unwrap(),
2756                res
2757            );
2758        }
2759    }
2760
2761    #[mz_ore::test]
2762    fn test_build_parsed_datetime_timestamp() {
2763        run_test_build_parsed_datetime_timestamp(
2764            "2000-01-02",
2765            ParsedDateTime {
2766                year: Some(DateTimeFieldValue::new(2000, 0)),
2767                month: Some(DateTimeFieldValue::new(1, 0)),
2768                day: Some(DateTimeFieldValue::new(2, 0)),
2769                ..Default::default()
2770            },
2771        );
2772        run_test_build_parsed_datetime_timestamp(
2773            "2000",
2774            ParsedDateTime {
2775                year: Some(DateTimeFieldValue::new(2000, 0)),
2776                ..Default::default()
2777            },
2778        );
2779        run_test_build_parsed_datetime_timestamp(
2780            "2000-1-",
2781            ParsedDateTime {
2782                year: Some(DateTimeFieldValue::new(2000, 0)),
2783                month: Some(DateTimeFieldValue::new(1, 0)),
2784                ..Default::default()
2785            },
2786        );
2787        run_test_build_parsed_datetime_timestamp(
2788            "2000-01-02 3:4:5.6",
2789            ParsedDateTime {
2790                year: Some(DateTimeFieldValue::new(2000, 0)),
2791                month: Some(DateTimeFieldValue::new(1, 0)),
2792                day: Some(DateTimeFieldValue::new(2, 0)),
2793                hour: Some(DateTimeFieldValue::new(3, 0)),
2794                minute: Some(DateTimeFieldValue::new(4, 0)),
2795                second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2796                ..Default::default()
2797            },
2798        );
2799        run_test_build_parsed_datetime_timestamp(
2800            "2000-01-02T3:4:5.6",
2801            ParsedDateTime {
2802                year: Some(DateTimeFieldValue::new(2000, 0)),
2803                month: Some(DateTimeFieldValue::new(1, 0)),
2804                day: Some(DateTimeFieldValue::new(2, 0)),
2805                hour: Some(DateTimeFieldValue::new(3, 0)),
2806                minute: Some(DateTimeFieldValue::new(4, 0)),
2807                second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2808                ..Default::default()
2809            },
2810        );
2811
2812        fn run_test_build_parsed_datetime_timestamp(test: &str, res: ParsedDateTime) {
2813            assert_eq!(
2814                ParsedDateTime::build_parsed_datetime_timestamp(test, CalendarEra::AD).unwrap(),
2815                res
2816            );
2817        }
2818    }
2819
2820    #[mz_ore::test]
2821    fn test_build_parsed_datetime_interval() {
2822        use DateTimeField::*;
2823        let test_cases = [
2824            (
2825                ParsedDateTime {
2826                    year: Some(DateTimeFieldValue::new(1, 0)),
2827                    month: Some(DateTimeFieldValue::new(2, 0)),
2828                    day: Some(DateTimeFieldValue::new(3, 0)),
2829                    hour: Some(DateTimeFieldValue::new(4, 0)),
2830                    minute: Some(DateTimeFieldValue::new(5, 0)),
2831                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2832                    ..Default::default()
2833                },
2834                "1-2 3 4:5:6.7",
2835                Second,
2836            ),
2837            (
2838                ParsedDateTime {
2839                    year: Some(DateTimeFieldValue::new(1, 0)),
2840                    month: Some(DateTimeFieldValue::new(2, 0)),
2841                    day: Some(DateTimeFieldValue::new(3, 0)),
2842                    hour: Some(DateTimeFieldValue::new(4, 0)),
2843                    minute: Some(DateTimeFieldValue::new(5, 0)),
2844                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2845                    ..Default::default()
2846                },
2847                "1 year 2 months 3 days 4 hours 5 minutes 6.7 seconds",
2848                Second,
2849            ),
2850            (
2851                ParsedDateTime {
2852                    second: Some(DateTimeFieldValue::new(1, 0)),
2853                    ..Default::default()
2854                },
2855                "1",
2856                Second,
2857            ),
2858            (
2859                ParsedDateTime {
2860                    day: Some(DateTimeFieldValue::new(1, 0)),
2861                    ..Default::default()
2862                },
2863                "1",
2864                Day,
2865            ),
2866            (
2867                ParsedDateTime {
2868                    month: Some(DateTimeFieldValue::new(1, 0)),
2869                    ..Default::default()
2870                },
2871                "1",
2872                Month,
2873            ),
2874            (
2875                ParsedDateTime {
2876                    hour: Some(DateTimeFieldValue::new(1, 0)),
2877                    minute: Some(DateTimeFieldValue::new(0, 0)),
2878                    second: Some(DateTimeFieldValue::new(0, 0)),
2879                    ..Default::default()
2880                },
2881                "1:",
2882                Second,
2883            ),
2884            (
2885                ParsedDateTime {
2886                    year: Some(DateTimeFieldValue::new(1, 0)),
2887                    month: Some(DateTimeFieldValue::new(0, 0)),
2888                    ..Default::default()
2889                },
2890                "1-",
2891                Second,
2892            ),
2893            (
2894                ParsedDateTime {
2895                    day: Some(DateTimeFieldValue::new(1, 0)),
2896                    hour: Some(DateTimeFieldValue::new(2, 0)),
2897                    minute: Some(DateTimeFieldValue::new(0, 0)),
2898                    second: Some(DateTimeFieldValue::new(0, 0)),
2899                    ..Default::default()
2900                },
2901                "1 2:",
2902                Second,
2903            ),
2904            (
2905                ParsedDateTime {
2906                    year: Some(DateTimeFieldValue::new(1, 0)),
2907                    month: Some(DateTimeFieldValue::new(2, 0)),
2908                    hour: Some(DateTimeFieldValue::new(3, 0)),
2909                    minute: Some(DateTimeFieldValue::new(4, 0)),
2910                    second: Some(DateTimeFieldValue::new(0, 0)),
2911                    ..Default::default()
2912                },
2913                "1-2 3:4",
2914                Second,
2915            ),
2916            (
2917                ParsedDateTime {
2918                    year: Some(DateTimeFieldValue::new(1, 0)),
2919                    month: Some(DateTimeFieldValue::new(0, 0)),
2920                    day: Some(DateTimeFieldValue::new(2, 0)),
2921                    hour: Some(DateTimeFieldValue::new(3, 0)),
2922                    minute: Some(DateTimeFieldValue::new(0, 0)),
2923                    second: Some(DateTimeFieldValue::new(0, 0)),
2924                    ..Default::default()
2925                },
2926                "1- 2 3:",
2927                Second,
2928            ),
2929            (
2930                ParsedDateTime {
2931                    year: Some(DateTimeFieldValue::new(5, 0)),
2932                    month: Some(DateTimeFieldValue::new(6, 0)),
2933                    hour: Some(DateTimeFieldValue::new(1, 0)),
2934                    minute: Some(DateTimeFieldValue::new(2, 0)),
2935                    second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2936                    ..Default::default()
2937                },
2938                "1:2:3.4 5-6",
2939                Second,
2940            ),
2941            (
2942                ParsedDateTime {
2943                    year: Some(DateTimeFieldValue::new(1, 0)),
2944                    month: Some(DateTimeFieldValue::new(2, 0)),
2945                    hour: Some(DateTimeFieldValue::new(3, 0)),
2946                    ..Default::default()
2947                },
2948                "1-2 3",
2949                Hour,
2950            ),
2951            (
2952                ParsedDateTime {
2953                    year: Some(DateTimeFieldValue::new(-1, 0)),
2954                    month: Some(DateTimeFieldValue::new(-2, 0)),
2955                    day: Some(DateTimeFieldValue::new(-3, 0)),
2956                    hour: Some(DateTimeFieldValue::new(-4, 0)),
2957                    minute: Some(DateTimeFieldValue::new(-5, 0)),
2958                    second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
2959                    ..Default::default()
2960                },
2961                "-1-2 -3 -4:5:6.7",
2962                Second,
2963            ),
2964            (
2965                ParsedDateTime {
2966                    year: Some(DateTimeFieldValue::new(-1, 0)),
2967                    month: Some(DateTimeFieldValue::new(-2, 0)),
2968                    day: Some(DateTimeFieldValue::new(3, 0)),
2969                    hour: Some(DateTimeFieldValue::new(-4, 0)),
2970                    minute: Some(DateTimeFieldValue::new(-5, 0)),
2971                    second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
2972                    ..Default::default()
2973                },
2974                "-1-2 3 -4:5:6.7",
2975                Second,
2976            ),
2977            (
2978                ParsedDateTime {
2979                    year: Some(DateTimeFieldValue::new(-1, 0)),
2980                    month: Some(DateTimeFieldValue::new(-2, 0)),
2981                    day: Some(DateTimeFieldValue::new(-3, 0)),
2982                    hour: Some(DateTimeFieldValue::new(4, 0)),
2983                    minute: Some(DateTimeFieldValue::new(0, 0)),
2984                    second: Some(DateTimeFieldValue::new(0, 500_000_000)),
2985                    ..Default::default()
2986                },
2987                "-1-2 -3 4::.5",
2988                Second,
2989            ),
2990            (
2991                ParsedDateTime {
2992                    hour: Some(DateTimeFieldValue::new(0, 0)),
2993                    minute: Some(DateTimeFieldValue::new(0, 0)),
2994                    second: Some(DateTimeFieldValue::new(-1, -270_000_000)),
2995                    ..Default::default()
2996                },
2997                "-::1.27",
2998                Second,
2999            ),
3000            (
3001                ParsedDateTime {
3002                    second: Some(DateTimeFieldValue::new(1, 270_000_000)),
3003                    ..Default::default()
3004                },
3005                ":::::1.27",
3006                Second,
3007            ),
3008            (
3009                ParsedDateTime {
3010                    year: Some(DateTimeFieldValue::new(1, 0)),
3011                    month: Some(DateTimeFieldValue::new(0, 0)),
3012                    day: Some(DateTimeFieldValue::new(2, 0)),
3013                    hour: Some(DateTimeFieldValue::new(3, 0)),
3014                    minute: Some(DateTimeFieldValue::new(0, 0)),
3015                    second: Some(DateTimeFieldValue::new(0, 0)),
3016                    ..Default::default()
3017                },
3018                ":::1- ::2 ::::3:",
3019                Second,
3020            ),
3021            (
3022                ParsedDateTime {
3023                    year: Some(DateTimeFieldValue::new(1, 0)),
3024                    month: Some(DateTimeFieldValue::new(2, 0)),
3025                    day: Some(DateTimeFieldValue::new(3, 0)),
3026                    hour: Some(DateTimeFieldValue::new(4, 0)),
3027                    minute: Some(DateTimeFieldValue::new(5, 0)),
3028                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3029                    ..Default::default()
3030                },
3031                "1 years 2 months 3 days 4 hours 5 minutes 6.7 seconds",
3032                Second,
3033            ),
3034            (
3035                ParsedDateTime {
3036                    year: Some(DateTimeFieldValue::new(1, 0)),
3037                    month: Some(DateTimeFieldValue::new(2, 0)),
3038                    day: Some(DateTimeFieldValue::new(3, 0)),
3039                    hour: Some(DateTimeFieldValue::new(4, 0)),
3040                    minute: Some(DateTimeFieldValue::new(5, 0)),
3041                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3042                    ..Default::default()
3043                },
3044                "1y 2mon 3d 4h 5m 6.7s",
3045                Second,
3046            ),
3047            (
3048                ParsedDateTime {
3049                    year: Some(DateTimeFieldValue::new(1, 0)),
3050                    month: Some(DateTimeFieldValue::new(2, 0)),
3051                    day: Some(DateTimeFieldValue::new(3, 0)),
3052                    hour: Some(DateTimeFieldValue::new(4, 0)),
3053                    minute: Some(DateTimeFieldValue::new(5, 0)),
3054                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3055                    ..Default::default()
3056                },
3057                "6.7 seconds 5 minutes 3 days 4 hours 1 year 2 month",
3058                Second,
3059            ),
3060            (
3061                ParsedDateTime {
3062                    year: Some(DateTimeFieldValue::new(-1, 0)),
3063                    month: Some(DateTimeFieldValue::new(2, 0)),
3064                    day: Some(DateTimeFieldValue::new(-3, 0)),
3065                    hour: Some(DateTimeFieldValue::new(4, 0)),
3066                    minute: Some(DateTimeFieldValue::new(5, 0)),
3067                    second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3068                    ..Default::default()
3069                },
3070                "-6.7 seconds 5 minutes -3 days 4 hours -1 year 2 month",
3071                Second,
3072            ),
3073            (
3074                ParsedDateTime {
3075                    year: Some(DateTimeFieldValue::new(1, 0)),
3076                    month: Some(DateTimeFieldValue::new(2, 300_000_000)),
3077                    day: Some(DateTimeFieldValue::new(4, 500_000_000)),
3078                    ..Default::default()
3079                },
3080                "1y 2.3mon 4.5d",
3081                Second,
3082            ),
3083            (
3084                ParsedDateTime {
3085                    year: Some(DateTimeFieldValue::new(-1, -200_000_000)),
3086                    month: Some(DateTimeFieldValue::new(2, 300_000_000)),
3087                    day: Some(DateTimeFieldValue::new(-3, -400_000_000)),
3088                    hour: Some(DateTimeFieldValue::new(4, 500_000_000)),
3089                    minute: Some(DateTimeFieldValue::new(5, 600_000_000)),
3090                    second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3091                    ..Default::default()
3092                },
3093                "-6.7 seconds 5.6 minutes -3.4 days 4.5 hours -1.2 year 2.3 month",
3094                Second,
3095            ),
3096            (
3097                ParsedDateTime {
3098                    day: Some(DateTimeFieldValue::new(1, 0)),
3099                    second: Some(DateTimeFieldValue::new(0, -270_000_000)),
3100                    ..Default::default()
3101                },
3102                "1 day -0.27 seconds",
3103                Second,
3104            ),
3105            (
3106                ParsedDateTime {
3107                    day: Some(DateTimeFieldValue::new(-1, 0)),
3108                    second: Some(DateTimeFieldValue::new(0, 270_000_000)),
3109                    ..Default::default()
3110                },
3111                "-1 day 0.27 seconds",
3112                Second,
3113            ),
3114            (
3115                ParsedDateTime {
3116                    year: Some(DateTimeFieldValue::new(10, 333_000_000)),
3117                    ..Default::default()
3118                },
3119                "10.333 years",
3120                Second,
3121            ),
3122            (
3123                ParsedDateTime {
3124                    year: Some(DateTimeFieldValue::new(10, 333_000_000)),
3125                    ..Default::default()
3126                },
3127                "10.333",
3128                Year,
3129            ),
3130            (
3131                ParsedDateTime {
3132                    year: Some(DateTimeFieldValue::new(1, 0)),
3133                    month: Some(DateTimeFieldValue::new(2, 0)),
3134                    day: Some(DateTimeFieldValue::new(5, 0)),
3135                    hour: Some(DateTimeFieldValue::new(3, 0)),
3136                    minute: Some(DateTimeFieldValue::new(4, 0)),
3137                    second: Some(DateTimeFieldValue::new(0, 0)),
3138                    ..Default::default()
3139                },
3140                "1-2 3:4 5 day",
3141                Second,
3142            ),
3143            (
3144                ParsedDateTime {
3145                    year: Some(DateTimeFieldValue::new(1, 0)),
3146                    month: Some(DateTimeFieldValue::new(2, 0)),
3147                    day: Some(DateTimeFieldValue::new(5, 0)),
3148                    hour: Some(DateTimeFieldValue::new(3, 0)),
3149                    minute: Some(DateTimeFieldValue::new(4, 0)),
3150                    second: Some(DateTimeFieldValue::new(0, 0)),
3151                    ..Default::default()
3152                },
3153                "5 day 3:4 1-2",
3154                Second,
3155            ),
3156            (
3157                ParsedDateTime {
3158                    year: Some(DateTimeFieldValue::new(1, 0)),
3159                    month: Some(DateTimeFieldValue::new(2, 0)),
3160                    day: Some(DateTimeFieldValue::new(5, 0)),
3161                    hour: Some(DateTimeFieldValue::new(3, 0)),
3162                    minute: Some(DateTimeFieldValue::new(4, 0)),
3163                    second: Some(DateTimeFieldValue::new(0, 0)),
3164                    ..Default::default()
3165                },
3166                "1-2 5 day 3:4",
3167                Second,
3168            ),
3169            (
3170                ParsedDateTime {
3171                    year: Some(DateTimeFieldValue::new(1, 0)),
3172                    day: Some(DateTimeFieldValue::new(2, 0)),
3173                    hour: Some(DateTimeFieldValue::new(3, 0)),
3174                    minute: Some(DateTimeFieldValue::new(4, 0)),
3175                    second: Some(DateTimeFieldValue::new(5, 600_000_000)),
3176                    ..Default::default()
3177                },
3178                "+1 year +2 days +3:4:5.6",
3179                Second,
3180            ),
3181            (
3182                ParsedDateTime {
3183                    year: Some(DateTimeFieldValue::new(1, 0)),
3184                    month: Some(DateTimeFieldValue::new(2, 0)),
3185                    ..Default::default()
3186                },
3187                "1-2",
3188                Month,
3189            ),
3190            (
3191                ParsedDateTime {
3192                    year: Some(DateTimeFieldValue::new(1, 0)),
3193                    month: Some(DateTimeFieldValue::new(2, 0)),
3194                    ..Default::default()
3195                },
3196                "1-2",
3197                Minute,
3198            ),
3199            (
3200                ParsedDateTime {
3201                    day: Some(DateTimeFieldValue::new(1, 999_999_999)),
3202                    ..Default::default()
3203                },
3204                "1.999999999999999999 days",
3205                Second,
3206            ),
3207            (
3208                ParsedDateTime {
3209                    millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
3210                    ..Default::default()
3211                },
3212                "1.2ms",
3213                Second,
3214            ),
3215            (
3216                ParsedDateTime {
3217                    millisecond: Some(DateTimeFieldValue::new(1, 0)),
3218                    ..Default::default()
3219                },
3220                "1ms",
3221                Second,
3222            ),
3223            (
3224                ParsedDateTime {
3225                    millisecond: Some(DateTimeFieldValue::new(2100, 0)),
3226                    ..Default::default()
3227                },
3228                "2100ms",
3229                Second,
3230            ),
3231            (
3232                ParsedDateTime {
3233                    hour: Some(DateTimeFieldValue::new(1, 0)),
3234                    millisecond: Some(DateTimeFieldValue::new(2, 0)),
3235                    ..Default::default()
3236                },
3237                "1h 2ms",
3238                Second,
3239            ),
3240            (
3241                ParsedDateTime {
3242                    millisecond: Some(DateTimeFieldValue::new(42, 900_000_000)),
3243                    ..Default::default()
3244                },
3245                "42.9 milliseconds",
3246                Second,
3247            ),
3248            (
3249                ParsedDateTime {
3250                    second: Some(DateTimeFieldValue::new(5, 0)),
3251                    millisecond: Some(DateTimeFieldValue::new(37, 660_000_000)),
3252                    ..Default::default()
3253                },
3254                "5.0 seconds 37.66 milliseconds",
3255                Second,
3256            ),
3257            (
3258                ParsedDateTime {
3259                    day: Some(DateTimeFieldValue::new(14, 0)),
3260                    millisecond: Some(DateTimeFieldValue::new(60, 0)),
3261                    ..Default::default()
3262                },
3263                "14 days 60 ms",
3264                Second,
3265            ),
3266            (
3267                ParsedDateTime {
3268                    microsecond: Some(DateTimeFieldValue::new(42, 900_000_000)),
3269                    ..Default::default()
3270                },
3271                "42.9 microseconds",
3272                Second,
3273            ),
3274            (
3275                ParsedDateTime {
3276                    second: Some(DateTimeFieldValue::new(5, 0)),
3277                    microsecond: Some(DateTimeFieldValue::new(37, 660_000_000)),
3278                    ..Default::default()
3279                },
3280                "5.0 seconds 37.66 microseconds",
3281                Second,
3282            ),
3283            (
3284                ParsedDateTime {
3285                    millennium: Some(DateTimeFieldValue::new(9, 800_000_000)),
3286                    ..Default::default()
3287                },
3288                "9.8 millenniums",
3289                Second,
3290            ),
3291            (
3292                ParsedDateTime {
3293                    century: Some(DateTimeFieldValue::new(7, 600_000_000)),
3294                    ..Default::default()
3295                },
3296                "7.6 centuries",
3297                Second,
3298            ),
3299            (
3300                ParsedDateTime {
3301                    decade: Some(DateTimeFieldValue::new(5, 400_000_000)),
3302                    ..Default::default()
3303                },
3304                "5.4 decades",
3305                Second,
3306            ),
3307            (
3308                ParsedDateTime {
3309                    year: Some(DateTimeFieldValue::new(1, 200_000_000)),
3310                    decade: Some(DateTimeFieldValue::new(4, 300_000_000)),
3311                    century: Some(DateTimeFieldValue::new(5, 600_000_000)),
3312                    millennium: Some(DateTimeFieldValue::new(8, 700_000_000)),
3313                    ..Default::default()
3314                },
3315                "8.7 mils 5.6 cent 4.3 decs 1.2 y",
3316                Second,
3317            ),
3318        ];
3319
3320        for test in test_cases.iter() {
3321            let actual =
3322                ParsedDateTime::build_parsed_datetime_interval(test.1, None, test.2).unwrap();
3323            if actual != test.0 {
3324                panic!(
3325                    "In test INTERVAL '{}' {}\n actual: {:?} \n expected: {:?}",
3326                    test.1, test.2, actual, test.0
3327                );
3328            }
3329        }
3330    }
3331
3332    #[mz_ore::test]
3333    fn test_build_parsed_datetime_interval_errors() {
3334        use DateTimeField::*;
3335        let test_cases = [
3336            ("1 year 2 years", Second, "YEAR field set twice"),
3337            ("1-2 3-4", Second, "YEAR or MONTH field set twice"),
3338            ("1-2 3 year", Second, "YEAR field set twice"),
3339            ("1-2 3", Month, "MONTH field set twice"),
3340            ("1-2 3:4 5", Second, "SECOND field set twice"),
3341            ("1:2:3.4 5-6 7", Year, "YEAR field set twice"),
3342            ("-:::::1.27", Second, "have unprocessed tokens 1.270000000"),
3343            (
3344                "-1 ::.27",
3345                Second,
3346                "Cannot determine format of all parts. Add explicit time components, e.g. \
3347                INTERVAL '1 day' or INTERVAL '1' DAY",
3348            ),
3349            ("1:2:3.4.5", Second, "have unprocessed tokens .500000000"),
3350            ("1+2:3.4", Second, "Cannot determine format of all parts"),
3351            ("1x2:3.4", Second, "unknown units x"),
3352            ("0 foo", Second, "unknown units foo"),
3353            ("1-2 3:4 5 second", Second, "SECOND field set twice"),
3354            (
3355                "1-2 5 second 3:4",
3356                Second,
3357                "HOUR, MINUTE, SECOND field set twice",
3358            ),
3359            (
3360                "1 2-3 4:5",
3361                Day,
3362                "Cannot determine format of all parts. Add explicit time components, e.g. \
3363                INTERVAL '1 day' or INTERVAL '1' DAY",
3364            ),
3365            (
3366                "9223372036854775808 months",
3367                Day,
3368                "Unable to parse value 9223372036854775808 as a number: number too large to fit in target type",
3369            ),
3370            (
3371                "-9223372036854775809 months",
3372                Day,
3373                "Unable to parse value 9223372036854775809 as a number: number too large to fit in target type",
3374            ),
3375            (
3376                "9223372036854775808 seconds",
3377                Day,
3378                "Unable to parse value 9223372036854775808 as a number: number too large to fit in target type",
3379            ),
3380            (
3381                "-9223372036854775809 seconds",
3382                Day,
3383                "Unable to parse value 9223372036854775809 as a number: number too large to fit in target type",
3384            ),
3385            (
3386                "1.234 second 5 ms",
3387                Second,
3388                "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3389            ),
3390            (
3391                "1.234 second 5 us",
3392                Second,
3393                "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3394            ),
3395            (
3396                "7 ms 4.321 second",
3397                Second,
3398                "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3399            ),
3400            (
3401                "7 us 4.321 second",
3402                Second,
3403                "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3404            ),
3405        ];
3406        for test in test_cases.iter() {
3407            match ParsedDateTime::build_parsed_datetime_interval(test.0, None, test.1) {
3408                Err(e) => assert_eq!(e.to_string(), test.2),
3409                Ok(pdt) => panic!(
3410                    "Test INTERVAL '{}' {} passed when expected to fail with {}, generated ParsedDateTime {:?}",
3411                    test.0, test.1, test.2, pdt,
3412                ),
3413            }
3414        }
3415    }
3416
3417    #[mz_ore::test]
3418    fn test_split_timestamp_string() {
3419        let test_cases = [
3420            (
3421                "1969-06-01 10:10:10.410 UTC",
3422                "1969-06-01 10:10:10.410",
3423                "UTC",
3424            ),
3425            (
3426                "1969-06-01 10:10:10.410+4:00",
3427                "1969-06-01 10:10:10.410",
3428                "+4:00",
3429            ),
3430            (
3431                "1969-06-01 10:10:10.410-4:00",
3432                "1969-06-01 10:10:10.410",
3433                "-4:00",
3434            ),
3435            ("1969-06-01 10:10:10.410", "1969-06-01 10:10:10.410", ""),
3436            ("1969-06-01 10:10:10.410+4", "1969-06-01 10:10:10.410", "+4"),
3437            ("1969-06-01 10:10:10.410-4", "1969-06-01 10:10:10.410", "-4"),
3438            ("1969-06-01 10:10:10+4:00", "1969-06-01 10:10:10", "+4:00"),
3439            ("1969-06-01 10:10:10-4:00", "1969-06-01 10:10:10", "-4:00"),
3440            ("1969-06-01 10:10:10 UTC", "1969-06-01 10:10:10", "UTC"),
3441            ("1969-06-01 10:10:10", "1969-06-01 10:10:10", ""),
3442            ("1969-06-01 10:10+4:00", "1969-06-01 10:10", "+4:00"),
3443            ("1969-06-01 10:10-4:00", "1969-06-01 10:10", "-4:00"),
3444            ("1969-06-01 10:10 UTC", "1969-06-01 10:10", "UTC"),
3445            ("1969-06-01 10:10", "1969-06-01 10:10", ""),
3446            ("1969-06-01 UTC", "1969-06-01", "UTC"),
3447            ("1969-06-01 +4:00", "1969-06-01", "+4:00"),
3448            ("1969-06-01 -4:00", "1969-06-01", "-4:00"),
3449            ("1969-06-01 +4", "1969-06-01", "+4"),
3450            ("1969-06-01 -4", "1969-06-01", "-4"),
3451            ("1969-06-01", "1969-06-01", ""),
3452            ("1969-06-01 10:10:10.410Z", "1969-06-01 10:10:10.410", "Z"),
3453            ("1969-06-01 10:10:10.410z", "1969-06-01 10:10:10.410", "z"),
3454            ("1969-06-01Z", "1969-06-01", "Z"),
3455            ("1969-06-01z", "1969-06-01", "z"),
3456            ("1969-06-01 10:10:10.410   ", "1969-06-01 10:10:10.410", ""),
3457            (
3458                "1969-06-01     10:10:10.410   ",
3459                "1969-06-01     10:10:10.410",
3460                "",
3461            ),
3462            ("   1969-06-01 10:10:10.412", "1969-06-01 10:10:10.412", ""),
3463            (
3464                "   1969-06-01 10:10:10.413   ",
3465                "1969-06-01 10:10:10.413",
3466                "",
3467            ),
3468            (
3469                "1969-06-01 10:10:10.410 +4:00",
3470                "1969-06-01 10:10:10.410",
3471                "+4:00",
3472            ),
3473            (
3474                "1969-06-01 10:10:10.410+4 :00",
3475                "1969-06-01 10:10:10.410",
3476                "+4 :00",
3477            ),
3478            (
3479                "1969-06-01 10:10:10.410      +4:00",
3480                "1969-06-01 10:10:10.410",
3481                "+4:00",
3482            ),
3483            (
3484                "1969-06-01 10:10:10.410+4:00     ",
3485                "1969-06-01 10:10:10.410",
3486                "+4:00",
3487            ),
3488            (
3489                "1969-06-01 10:10:10.410  Z  ",
3490                "1969-06-01 10:10:10.410",
3491                "Z",
3492            ),
3493            ("1969-06-01    +4  ", "1969-06-01", "+4"),
3494            ("1969-06-01   Z   ", "1969-06-01", "Z"),
3495        ];
3496
3497        for test in test_cases.iter() {
3498            let (ts, tz, era) = split_timestamp_string(test.0);
3499
3500            assert_eq!(ts, test.1);
3501            assert_eq!(tz, test.2);
3502            assert_eq!(era, CalendarEra::AD);
3503        }
3504    }
3505
3506    #[mz_ore::test]
3507    fn proptest_packed_naive_time_roundtrips() {
3508        let strat = add_arb_duration(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
3509        proptest!(|(time in strat)| {
3510            let packed = PackedNaiveTime::from_value(time);
3511            let rnd = packed.into_value();
3512            prop_assert_eq!(time, rnd);
3513        });
3514    }
3515
3516    #[mz_ore::test]
3517    fn proptest_packed_naive_time_sort_order() {
3518        let time = add_arb_duration(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
3519        let strat = proptest::collection::vec(time, 0..128);
3520        proptest!(|(mut times in strat)| {
3521            let mut packed: Vec<_> = times.iter().copied()
3522                .map(PackedNaiveTime::from_value).collect();
3523
3524            times.sort();
3525            packed.sort();
3526
3527            for (time, packed) in times.into_iter().zip_eq(packed.into_iter()) {
3528                let rnd = packed.into_value();
3529                prop_assert_eq!(time, rnd);
3530            }
3531        });
3532    }
3533}
3534
3535#[mz_ore::test]
3536fn test_parseddatetime_add_field() {
3537    use DateTimeField::*;
3538    let pdt_unit = ParsedDateTime {
3539        millennium: Some(DateTimeFieldValue::new(8, 0)),
3540        century: Some(DateTimeFieldValue::new(9, 0)),
3541        decade: Some(DateTimeFieldValue::new(10, 0)),
3542        year: Some(DateTimeFieldValue::new(1, 0)),
3543        month: Some(DateTimeFieldValue::new(2, 0)),
3544        day: Some(DateTimeFieldValue::new(2, 0)),
3545        hour: Some(DateTimeFieldValue::new(3, 0)),
3546        minute: Some(DateTimeFieldValue::new(4, 0)),
3547        second: Some(DateTimeFieldValue::new(5, 0)),
3548        millisecond: Some(DateTimeFieldValue::new(6, 0)),
3549        microsecond: Some(DateTimeFieldValue::new(7, 0)),
3550        ..Default::default()
3551    };
3552
3553    let pdt_frac = ParsedDateTime {
3554        millennium: Some(DateTimeFieldValue::new(8, 555_555_555)),
3555        century: Some(DateTimeFieldValue::new(9, 555_555_555)),
3556        decade: Some(DateTimeFieldValue::new(10, 555_555_555)),
3557        year: Some(DateTimeFieldValue::new(1, 555_555_555)),
3558        month: Some(DateTimeFieldValue::new(2, 555_555_555)),
3559        day: Some(DateTimeFieldValue::new(2, 555_555_555)),
3560        hour: Some(DateTimeFieldValue::new(3, 555_555_555)),
3561        minute: Some(DateTimeFieldValue::new(4, 555_555_555)),
3562        second: Some(DateTimeFieldValue::new(5, 555_555_555)),
3563        millisecond: Some(DateTimeFieldValue::new(6, 555_555_555)),
3564        microsecond: Some(DateTimeFieldValue::new(7, 555_555_555)),
3565        ..Default::default()
3566    };
3567
3568    let pdt_frac_neg = ParsedDateTime {
3569        millennium: Some(DateTimeFieldValue::new(-8, -555_555_555)),
3570        century: Some(DateTimeFieldValue::new(-9, -555_555_555)),
3571        decade: Some(DateTimeFieldValue::new(-10, -555_555_555)),
3572        year: Some(DateTimeFieldValue::new(-1, -555_555_555)),
3573        month: Some(DateTimeFieldValue::new(-2, -555_555_555)),
3574        day: Some(DateTimeFieldValue::new(-2, -555_555_555)),
3575        hour: Some(DateTimeFieldValue::new(-3, -555_555_555)),
3576        minute: Some(DateTimeFieldValue::new(-4, -555_555_555)),
3577        second: Some(DateTimeFieldValue::new(-5, -555_555_555)),
3578        millisecond: Some(DateTimeFieldValue::new(-6, -555_555_555)),
3579        microsecond: Some(DateTimeFieldValue::new(-7, -555_555_555)),
3580        ..Default::default()
3581    };
3582
3583    let pdt_s_rollover = ParsedDateTime {
3584        millisecond: Some(DateTimeFieldValue::new(1002, 666_666_666)),
3585        microsecond: Some(DateTimeFieldValue::new(1000003, 777_777_777)),
3586        ..Default::default()
3587    };
3588
3589    run_test_parseddatetime_add_field(pdt_unit.clone(), Millennium, (8 * 12 * 1_000, 0, 0));
3590    run_test_parseddatetime_add_field(pdt_unit.clone(), Century, (9 * 12 * 100, 0, 0));
3591    run_test_parseddatetime_add_field(pdt_unit.clone(), Decade, (10 * 12 * 10, 0, 0));
3592    run_test_parseddatetime_add_field(pdt_unit.clone(), Year, (12, 0, 0));
3593    run_test_parseddatetime_add_field(pdt_unit.clone(), Month, (2, 0, 0));
3594    run_test_parseddatetime_add_field(pdt_unit.clone(), Day, (0, 2, 0));
3595    run_test_parseddatetime_add_field(pdt_unit.clone(), Hour, (0, 0, 3 * 60 * 60 * 1_000_000));
3596    run_test_parseddatetime_add_field(pdt_unit.clone(), Minute, (0, 0, 4 * 60 * 1_000_000));
3597    run_test_parseddatetime_add_field(pdt_unit.clone(), Second, (0, 0, 5 * 1_000_000));
3598    run_test_parseddatetime_add_field(pdt_unit.clone(), Milliseconds, (0, 0, 6 * 1_000));
3599    run_test_parseddatetime_add_field(pdt_unit, Microseconds, (0, 0, 7));
3600    run_test_parseddatetime_add_field(pdt_frac.clone(), Millennium, (102_666, 0, 0));
3601    run_test_parseddatetime_add_field(pdt_frac.clone(), Century, (11466, 0, 0));
3602    run_test_parseddatetime_add_field(pdt_frac.clone(), Decade, (1266, 0, 0));
3603    run_test_parseddatetime_add_field(pdt_frac.clone(), Year, (18, 0, 0));
3604    run_test_parseddatetime_add_field(
3605        pdt_frac.clone(),
3606        Month,
3607        (
3608            2,
3609            16,
3610            // 15:59:59.99856
3611            (15 * 60 * 60 * 1_000_000) + (59 * 60 * 1_000_000) + (59 * 1_000_000) + 998_560,
3612        ),
3613    );
3614    run_test_parseddatetime_add_field(
3615        pdt_frac.clone(),
3616        Day,
3617        (
3618            0,
3619            2,
3620            // 13:19:59.999952
3621            (13 * 60 * 60 * 1_000_000) + (19 * 60 * 1_000_000) + (59 * 1_000_000) + 999_952,
3622        ),
3623    );
3624    run_test_parseddatetime_add_field(
3625        pdt_frac.clone(),
3626        Hour,
3627        (
3628            0,
3629            0,
3630            // 03:33:19.999998
3631            (3 * 60 * 60 * 1_000_000) + (33 * 60 * 1_000_000) + (19 * 1_000_000) + 999_998,
3632        ),
3633    );
3634    run_test_parseddatetime_add_field(
3635        pdt_frac.clone(),
3636        Minute,
3637        (
3638            0,
3639            0,
3640            // 00:04:33.333333
3641            (4 * 60 * 1_000_000) + (33 * 1_000_000) + 333_333,
3642        ),
3643    );
3644    run_test_parseddatetime_add_field(
3645        pdt_frac.clone(),
3646        Second,
3647        (
3648            0,
3649            0,
3650            // 00:00:05.555556
3651            (5 * 1_000_000) + 555_556,
3652        ),
3653    );
3654    run_test_parseddatetime_add_field(
3655        pdt_frac.clone(),
3656        Milliseconds,
3657        (
3658            0, 0, // 00:00:00.006556
3659            6_556,
3660        ),
3661    );
3662    run_test_parseddatetime_add_field(
3663        pdt_frac,
3664        Microseconds,
3665        (
3666            0, 0, // 00:00:00.000008
3667            8,
3668        ),
3669    );
3670    run_test_parseddatetime_add_field(pdt_frac_neg.clone(), Year, (-18, 0, 0));
3671    run_test_parseddatetime_add_field(
3672        pdt_frac_neg.clone(),
3673        Month,
3674        (
3675            -2,
3676            -16,
3677            // -15:59:59.99856
3678            (-15 * 60 * 60 * 1_000_000) + (-59 * 60 * 1_000_000) + (-59 * 1_000_000) + -998_560,
3679        ),
3680    );
3681    run_test_parseddatetime_add_field(
3682        pdt_frac_neg.clone(),
3683        Day,
3684        (
3685            0,
3686            -2,
3687            // 13:19:59.999952
3688            (-13 * 60 * 60 * 1_000_000) + (-19 * 60 * 1_000_000) + (-59 * 1_000_000) + -999_952,
3689        ),
3690    );
3691    run_test_parseddatetime_add_field(
3692        pdt_frac_neg.clone(),
3693        Hour,
3694        (
3695            0,
3696            0,
3697            // -03:33:19.999998
3698            (-3 * 60 * 60 * 1_000_000) + (-33 * 60 * 1_000_000) + (-19 * 1_000_000) + -999_998,
3699        ),
3700    );
3701    run_test_parseddatetime_add_field(
3702        pdt_frac_neg.clone(),
3703        Minute,
3704        (
3705            0,
3706            0,
3707            // -00:04:33.333333
3708            (-4 * 60 * 1_000_000) + (-33 * 1_000_000) + -333_333,
3709        ),
3710    );
3711    run_test_parseddatetime_add_field(
3712        pdt_frac_neg.clone(),
3713        Second,
3714        (
3715            0,
3716            0,
3717            // -00:00:05.555556
3718            (-5 * 1_000_000) + -555_556,
3719        ),
3720    );
3721    run_test_parseddatetime_add_field(
3722        pdt_frac_neg.clone(),
3723        Milliseconds,
3724        (
3725            0, 0, // -00:00:00.006556
3726            -6_556,
3727        ),
3728    );
3729    run_test_parseddatetime_add_field(
3730        pdt_frac_neg,
3731        Microseconds,
3732        (
3733            0, 0, // -00:00:00.000008
3734            -8,
3735        ),
3736    );
3737    run_test_parseddatetime_add_field(
3738        pdt_s_rollover.clone(),
3739        Milliseconds,
3740        (
3741            0,
3742            0, // 00:00:01.002667
3743            (1 * 1_000_000) + 2_667,
3744        ),
3745    );
3746    run_test_parseddatetime_add_field(
3747        pdt_s_rollover,
3748        Microseconds,
3749        (
3750            0,
3751            0, // 00:00:01.000004
3752            (1 * 1_000_000) + 4,
3753        ),
3754    );
3755
3756    fn run_test_parseddatetime_add_field(
3757        pdt: ParsedDateTime,
3758        f: DateTimeField,
3759        expected: (i32, i32, i64),
3760    ) {
3761        let mut res = (0, 0, 0);
3762
3763        pdt.add_field(f, &mut res.0, &mut res.1, &mut res.2)
3764            .unwrap();
3765
3766        if res.0 != expected.0 || res.1 != expected.1 || res.2 != expected.2 {
3767            panic!(
3768                "test_parseddatetime_add_field failed \n actual: {:?} \n expected: {:?}",
3769                res, expected
3770            );
3771        }
3772    }
3773}
3774
3775#[mz_ore::test]
3776fn test_parseddatetime_compute_interval() {
3777    run_test_parseddatetime_compute_interval(
3778        ParsedDateTime {
3779            year: Some(DateTimeFieldValue::new(1, 0)),
3780            month: Some(DateTimeFieldValue::new(1, 0)),
3781            ..Default::default()
3782        },
3783        Interval {
3784            months: 13,
3785            ..Default::default()
3786        },
3787    );
3788    run_test_parseddatetime_compute_interval(
3789        ParsedDateTime {
3790            year: Some(DateTimeFieldValue::new(1, 0)),
3791            month: Some(DateTimeFieldValue::new(-1, 0)),
3792            ..Default::default()
3793        },
3794        Interval {
3795            months: 11,
3796            ..Default::default()
3797        },
3798    );
3799    run_test_parseddatetime_compute_interval(
3800        ParsedDateTime {
3801            year: Some(DateTimeFieldValue::new(-1, 0)),
3802            month: Some(DateTimeFieldValue::new(1, 0)),
3803            ..Default::default()
3804        },
3805        Interval {
3806            months: -11,
3807            ..Default::default()
3808        },
3809    );
3810    run_test_parseddatetime_compute_interval(
3811        ParsedDateTime {
3812            day: Some(DateTimeFieldValue::new(1, 0)),
3813            hour: Some(DateTimeFieldValue::new(-2, 0)),
3814            minute: Some(DateTimeFieldValue::new(-3, 0)),
3815            second: Some(DateTimeFieldValue::new(-4, -500_000_000)),
3816            ..Default::default()
3817        },
3818        // 1 day -2:03:04.5
3819        Interval::new(
3820            0,
3821            1,
3822            (-2 * 60 * 60 * 1_000_000) + (-3 * 60 * 1_000_000) + (-4 * 1_000_000) + -500_000,
3823        ),
3824    );
3825    run_test_parseddatetime_compute_interval(
3826        ParsedDateTime {
3827            day: Some(DateTimeFieldValue::new(-1, 0)),
3828            hour: Some(DateTimeFieldValue::new(2, 0)),
3829            minute: Some(DateTimeFieldValue::new(3, 0)),
3830            second: Some(DateTimeFieldValue::new(4, 500_000_000)),
3831            ..Default::default()
3832        },
3833        // -1 day 02:03:04.5
3834        Interval::new(
3835            0,
3836            -1,
3837            (2 * 60 * 60 * 1_000_000) + (3 * 60 * 1_000_000) + (4 * 1_000_000) + 500_000,
3838        ),
3839    );
3840    run_test_parseddatetime_compute_interval(
3841        ParsedDateTime {
3842            day: Some(DateTimeFieldValue::new(1, 0)),
3843            second: Some(DateTimeFieldValue::new(0, -270_000_000)),
3844            ..Default::default()
3845        },
3846        // 1 day -00:00:00.27
3847        Interval::new(0, 1, -270_000),
3848    );
3849    run_test_parseddatetime_compute_interval(
3850        ParsedDateTime {
3851            day: Some(DateTimeFieldValue::new(-1, 0)),
3852            second: Some(DateTimeFieldValue::new(0, 270_000_000)),
3853            ..Default::default()
3854        },
3855        // -1 day 00:00:00.27
3856        Interval::new(0, -1, 270_000),
3857    );
3858    run_test_parseddatetime_compute_interval(
3859        ParsedDateTime {
3860            year: Some(DateTimeFieldValue::new(-1, -555_555_555)),
3861            month: Some(DateTimeFieldValue::new(2, 555_555_555)),
3862            day: Some(DateTimeFieldValue::new(-3, -555_555_555)),
3863            hour: Some(DateTimeFieldValue::new(4, 555_555_555)),
3864            minute: Some(DateTimeFieldValue::new(-5, -555_555_555)),
3865            second: Some(DateTimeFieldValue::new(6, 555_555_555)),
3866            ..Default::default()
3867        },
3868        // -1 year -4 months +13 days +07:07:53.220829
3869        Interval::new(
3870            -16,
3871            13,
3872            (7 * 60 * 60 * 1_000_000) + (7 * 60 * 1_000_000) + (53 * 1_000_000) + 220_829,
3873        ),
3874    );
3875    run_test_parseddatetime_compute_interval(
3876        ParsedDateTime {
3877            second: Some(DateTimeFieldValue::new(1, 0)),
3878            millisecond: Some(DateTimeFieldValue::new(2_003, 0)),
3879            ..Default::default()
3880        },
3881        // 00:00:03.003
3882        Interval::new(0, 0, (3 * 1_000_000) + 3_000),
3883    );
3884    run_test_parseddatetime_compute_interval(
3885        ParsedDateTime {
3886            second: Some(DateTimeFieldValue::new(1, 0)),
3887            microsecond: Some(DateTimeFieldValue::new(2_000_003, 0)),
3888            ..Default::default()
3889        },
3890        // 00:00:03.000003
3891        Interval::new(0, 0, (3 * 1_000_000) + 3),
3892    );
3893    run_test_parseddatetime_compute_interval(
3894        ParsedDateTime {
3895            millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
3896            microsecond: Some(DateTimeFieldValue::new(3, 400_000_000)),
3897            ..Default::default()
3898        },
3899        // 00:00:00.0012034
3900        Interval::new(0, 0, 1_203),
3901    );
3902    run_test_parseddatetime_compute_interval(
3903        ParsedDateTime {
3904            millennium: Some(DateTimeFieldValue::new(1, 0)),
3905            century: Some(DateTimeFieldValue::new(2, 0)),
3906            decade: Some(DateTimeFieldValue::new(3, 0)),
3907            year: Some(DateTimeFieldValue::new(4, 0)),
3908            ..Default::default()
3909        },
3910        // 1234 years
3911        Interval::new(1234 * 12, 0, 0),
3912    );
3913
3914    fn run_test_parseddatetime_compute_interval(pdt: ParsedDateTime, expected: Interval) {
3915        let actual = pdt.compute_interval().unwrap();
3916
3917        if actual != expected {
3918            panic!(
3919                "test_interval_compute_interval failed\n input {:?}\nactual {:?}\nexpected {:?}",
3920                pdt, actual, expected
3921            )
3922        }
3923    }
3924}