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