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