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 u.is_some() {
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 u.as_ref().unwrap().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
1877impl CalendarEra {
1878    fn as_str(&self) -> &'static str {
1879        match self {
1880            CalendarEra::BC => "BC",
1881            CalendarEra::AD => "AD",
1882        }
1883    }
1884}
1885
1886/// Takes a 'date timezone' 'date time timezone' string and splits it into 'date
1887/// {time}' and 'timezone' components then checks for a 'CalenderEra' defaulting
1888/// to 'AD'.
1889pub(crate) fn split_timestamp_string(value: &str) -> (&str, &str, CalendarEra) {
1890    // First we need to see if the string contains " +" or " -" because
1891    // timestamps can come in a format YYYY-MM-DD {+|-}<tz> (where the timezone
1892    // string can have colons)
1893    let cut = value.find(" +").or_else(|| value.find(" -"));
1894
1895    if let Some(cut) = cut {
1896        let (datetime, timezone) = value.split_at(cut);
1897
1898        let (timezone, era) = strip_era_from_timezone(timezone);
1899
1900        return (datetime.trim(), timezone.trim(), era);
1901    }
1902
1903    // If we have a hh:mm:dd component, we need to go past that to see if we can
1904    // find a tz
1905    let colon = value.find(':');
1906
1907    if let Some(colon) = colon {
1908        let substring = value.get(colon..);
1909        if let Some(substring) = substring {
1910            let tz = substring
1911                .find(|c: char| (c == '-') || (c == '+') || (c == ' ') || c.is_ascii_alphabetic());
1912
1913            if let Some(tz) = tz {
1914                let (datetime, timezone) = value.split_at(colon + tz);
1915
1916                let (timezone, era) = strip_era_from_timezone(timezone);
1917
1918                return (datetime.trim(), timezone.trim(), era);
1919            }
1920        }
1921
1922        (value.trim(), "", CalendarEra::AD)
1923    } else {
1924        // We don't have a time, so the only formats available are YYY-mm-dd<tz>
1925        // or YYYY-MM-dd <tz> Numeric offset timezones need to be separated from
1926        // the ymd by a space.
1927        let cut = value.find(|c: char| c.is_ascii_alphabetic());
1928
1929        if let Some(cut) = cut {
1930            let (datetime, timezone) = value.split_at(cut);
1931
1932            let (timezone, era) = strip_era_from_timezone(timezone);
1933
1934            return (datetime.trim(), timezone.trim(), era);
1935        }
1936
1937        (value.trim(), "", CalendarEra::AD)
1938    }
1939}
1940
1941fn strip_era_from_timezone(timezone: &str) -> (&str, CalendarEra) {
1942    use CalendarEra::{AD, BC};
1943    let timezone = timezone.trim();
1944    let timezone_upper = timezone.to_uppercase();
1945
1946    match (
1947        timezone_upper.strip_suffix(BC.as_str()),
1948        timezone_upper.strip_suffix(AD.as_str()),
1949    ) {
1950        (Some(remainder), None) => (&timezone[..remainder.len()], BC),
1951        (None, Some(remainder)) => (&timezone[..remainder.len()], AD),
1952        _ => (timezone, AD),
1953    }
1954}
1955
1956/// An encoded packed variant of [`NaiveTime`].
1957///
1958/// We uphold the invariant that [`PackedNaiveTime`] sorts the same as
1959/// [`NaiveTime`].
1960#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
1961pub struct PackedNaiveTime([u8; Self::SIZE]);
1962
1963impl FixedSizeCodec<NaiveTime> for PackedNaiveTime {
1964    const SIZE: usize = 8;
1965
1966    fn as_bytes(&self) -> &[u8] {
1967        &self.0
1968    }
1969
1970    fn from_bytes(slice: &[u8]) -> Result<Self, String> {
1971        let buf: [u8; Self::SIZE] = slice.try_into().map_err(|_| {
1972            format!(
1973                "size for PackedNaiveTime is {} bytes, got {}",
1974                Self::SIZE,
1975                slice.len()
1976            )
1977        })?;
1978        Ok(PackedNaiveTime(buf))
1979    }
1980
1981    #[inline]
1982    fn from_value(value: NaiveTime) -> Self {
1983        let secs = value.num_seconds_from_midnight();
1984        let nano = value.nanosecond();
1985
1986        let mut buf = [0u8; Self::SIZE];
1987
1988        (buf[..4]).copy_from_slice(&secs.to_be_bytes());
1989        (buf[4..]).copy_from_slice(&nano.to_be_bytes());
1990
1991        PackedNaiveTime(buf)
1992    }
1993
1994    #[inline]
1995    fn into_value(self) -> NaiveTime {
1996        let mut secs = [0u8; 4];
1997        secs.copy_from_slice(&self.0[..4]);
1998        let secs = u32::from_be_bytes(secs);
1999
2000        let mut nano = [0u8; 4];
2001        nano.copy_from_slice(&self.0[4..]);
2002        let nano = u32::from_be_bytes(nano);
2003
2004        NaiveTime::from_num_seconds_from_midnight_opt(secs, nano)
2005            .expect("NaiveTime roundtrips with PackedNaiveTime")
2006    }
2007}
2008
2009#[cfg(test)]
2010mod tests {
2011    use mz_ore::assert_ok;
2012    use mz_proto::protobuf_roundtrip;
2013    use proptest::prelude::any;
2014    use proptest::{prop_assert_eq, proptest};
2015
2016    use crate::scalar::add_arb_duration;
2017
2018    use super::*;
2019
2020    #[mz_ore::test]
2021    fn iterate_datetimefield() {
2022        use DateTimeField::*;
2023        assert_eq!(
2024            Millennium.into_iter().take(10).collect::<Vec<_>>(),
2025            vec![
2026                Century,
2027                Decade,
2028                Year,
2029                Month,
2030                Day,
2031                Hour,
2032                Minute,
2033                Second,
2034                Milliseconds,
2035                Microseconds
2036            ]
2037        )
2038    }
2039
2040    #[mz_ore::test]
2041    fn test_expected_dur_like_tokens() {
2042        use DateTimeField::*;
2043        use TimeStrToken::*;
2044        assert_eq!(
2045            expected_sql_standard_interval_tokens(Hour),
2046            vec![Num(0, 1), Colon, Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2047        );
2048        assert_eq!(
2049            expected_sql_standard_interval_tokens(Minute),
2050            vec![Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2051        );
2052        assert_eq!(
2053            expected_sql_standard_interval_tokens(Second),
2054            vec![Num(0, 1), Dot, Nanos(0)]
2055        );
2056    }
2057
2058    #[mz_ore::test]
2059    fn test_expected_sql_standard_interval_tokens() {
2060        use DateTimeField::*;
2061        use TimeStrToken::*;
2062        assert_eq!(
2063            expected_sql_standard_interval_tokens(Year),
2064            vec![Num(0, 1), Dash, Num(0, 1), Delim]
2065        );
2066
2067        assert_eq!(
2068            expected_sql_standard_interval_tokens(Day),
2069            vec![Num(0, 1), Delim]
2070        );
2071        assert_eq!(
2072            expected_sql_standard_interval_tokens(Hour),
2073            vec![Num(0, 1), Colon, Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2074        );
2075    }
2076    #[mz_ore::test]
2077    fn test_trim_and_return_sign() {
2078        let test_cases = [
2079            ("-2", -1, "2"),
2080            ("3", 1, "3"),
2081            ("+5", 1, "5"),
2082            ("-", -1, ""),
2083            ("-YEAR", -1, "YEAR"),
2084            ("YEAR", 1, "YEAR"),
2085        ];
2086
2087        for test in test_cases.iter() {
2088            let mut s = tokenize_time_str(test.0).unwrap();
2089
2090            assert_eq!(trim_and_return_sign(&mut s), test.1);
2091            assert_eq!(s.front(), tokenize_time_str(test.2).unwrap().front());
2092        }
2093    }
2094    #[mz_ore::test]
2095    fn test_determine_format_w_datetimefield() {
2096        use DateTimeField::*;
2097        use TimePartFormat::*;
2098
2099        let test_cases = [
2100            ("1-2 3", Some(SqlStandard(Year))),
2101            ("4:5", Some(SqlStandard(Hour))),
2102            ("4:5.6", Some(SqlStandard(Minute))),
2103            ("-4:5.6", Some(SqlStandard(Minute))),
2104            ("+4:5.6", Some(SqlStandard(Minute))),
2105            ("year", Some(PostgreSql(Year))),
2106            ("4year", Some(PostgreSql(Year))),
2107            ("-4year", Some(PostgreSql(Year))),
2108            ("5", None),
2109            ("5.6", None),
2110            ("3 4:5:6.7", None),
2111        ];
2112
2113        for test in test_cases.iter() {
2114            let s = tokenize_time_str(test.0).unwrap();
2115
2116            match (
2117                determine_format_w_datetimefield(s, None).unwrap(),
2118                test.1.as_ref(),
2119            ) {
2120                (Some(a), Some(b)) => {
2121                    if a != *b {
2122                        panic!(
2123                            "determine_format_w_datetimefield_and_time returned {:?}, expected {:?}",
2124                            a, b,
2125                        )
2126                    }
2127                }
2128                (None, None) => {}
2129                (x, y) => panic!(
2130                    "determine_format_w_datetimefield_and_time returned {:?}, expected {:?}",
2131                    x, y,
2132                ),
2133            }
2134        }
2135    }
2136    #[mz_ore::test]
2137    fn test_determine_format_w_datetimefield_and_leading_time() {
2138        use DateTimeField::*;
2139        use TimePartFormat::*;
2140
2141        assert_eq!(
2142            determine_format_w_datetimefield(tokenize_time_str("4:5").unwrap(), None,).unwrap(),
2143            Some(SqlStandard(Hour))
2144        );
2145        assert_eq!(
2146            determine_format_w_datetimefield(
2147                tokenize_time_str("4:5").unwrap(),
2148                Some(DateTimeField::Minute),
2149            )
2150            .unwrap(),
2151            Some(SqlStandard(Minute))
2152        );
2153        assert_eq!(
2154            determine_format_w_datetimefield(
2155                tokenize_time_str("4:5").unwrap(),
2156                Some(DateTimeField::Hour),
2157            )
2158            .unwrap(),
2159            Some(SqlStandard(Hour))
2160        );
2161    }
2162    #[mz_ore::test]
2163    fn test_determine_format_w_datetimefield_error() {
2164        let test_cases = [
2165            ("1+2", "Cannot determine format of all parts"),
2166            ("1:2+3", "Cannot determine format of all parts"),
2167            ("1:1YEAR2", "Cannot determine format of all parts"),
2168        ];
2169
2170        for test in test_cases.iter() {
2171            let s = tokenize_time_str(test.0).unwrap();
2172            match determine_format_w_datetimefield(s, None) {
2173                Err(e) => assert_eq!(e.to_string(), test.1),
2174                Ok(f) => panic!(
2175                    "Test passed when expected to fail: {}, generated {:?}",
2176                    test.0, f
2177                ),
2178            };
2179        }
2180    }
2181
2182    #[mz_ore::test]
2183    fn test_fill_pdt_from_tokens() {
2184        use DateTimeField::*;
2185        let test_cases = [
2186            (
2187                ParsedDateTime {
2188                    year: Some(DateTimeFieldValue::new(1, 0)),
2189                    month: Some(DateTimeFieldValue::new(2, 0)),
2190                    day: Some(DateTimeFieldValue::new(3, 0)),
2191                    hour: Some(DateTimeFieldValue::new(4, 0)),
2192                    minute: Some(DateTimeFieldValue::new(5, 0)),
2193                    second: Some(DateTimeFieldValue::new(6, 0)),
2194                    ..Default::default()
2195                },
2196                "1 2 3 4 5 6",
2197                "0 0 0 0 0 0",
2198                Year,
2199                1,
2200            ),
2201            (
2202                ParsedDateTime {
2203                    day: Some(DateTimeFieldValue::new(4, 0)),
2204                    hour: Some(DateTimeFieldValue::new(5, 0)),
2205                    minute: Some(DateTimeFieldValue::new(6, 0)),
2206                    ..Default::default()
2207                },
2208                "4 5 6",
2209                "0 0 0",
2210                Day,
2211                1,
2212            ),
2213            (
2214                ParsedDateTime {
2215                    day: Some(DateTimeFieldValue::new(-4, 0)),
2216                    hour: Some(DateTimeFieldValue::new(-5, 0)),
2217                    minute: Some(DateTimeFieldValue::new(-6, 0)),
2218                    ..Default::default()
2219                },
2220                "4 5 6",
2221                "0 0 0",
2222                Day,
2223                -1,
2224            ),
2225            // Mixed delimiter parsing
2226            (
2227                ParsedDateTime {
2228                    year: Some(DateTimeFieldValue::new(1, 0)),
2229                    month: Some(DateTimeFieldValue::new(2, 0)),
2230                    day: Some(DateTimeFieldValue::new(3, 0)),
2231                    hour: Some(DateTimeFieldValue::new(4, 0)),
2232                    minute: Some(DateTimeFieldValue::new(5, 0)),
2233                    second: Some(DateTimeFieldValue::new(6, 0)),
2234                    ..Default::default()
2235                },
2236                "1-2:3-4 5 6",
2237                "0-0:0-0 0 0",
2238                Year,
2239                1,
2240            ),
2241            // Skip an element at the end
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(5, 0)),
2248                    minute: Some(DateTimeFieldValue::new(6, 0)),
2249                    ..Default::default()
2250                },
2251                "1 2 3 5 6",
2252                "0 0 0 0 0 0",
2253                Year,
2254                1,
2255            ),
2256            // Skip an element w/ non-space parsing
2257            (
2258                ParsedDateTime {
2259                    year: Some(DateTimeFieldValue::new(1, 0)),
2260                    month: Some(DateTimeFieldValue::new(2, 0)),
2261                    day: Some(DateTimeFieldValue::new(3, 0)),
2262                    minute: Some(DateTimeFieldValue::new(5, 0)),
2263                    second: Some(DateTimeFieldValue::new(6, 0)),
2264                    ..Default::default()
2265                },
2266                "1-2:3- 5 6",
2267                "0-0:0-0 0 0",
2268                Year,
2269                1,
2270            ),
2271            // Get Nanos from tokenizer
2272            (
2273                ParsedDateTime {
2274                    year: Some(DateTimeFieldValue::new(1, 0)),
2275                    month: Some(DateTimeFieldValue::new(2, 0)),
2276                    day: Some(DateTimeFieldValue::new(3, 0)),
2277                    hour: Some(DateTimeFieldValue::new(4, 0)),
2278                    minute: Some(DateTimeFieldValue::new(5, 0)),
2279                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2280                    ..Default::default()
2281                },
2282                "1-2:3-4 5 6.7",
2283                "0-0:0-0 0 0.0",
2284                Year,
2285                1,
2286            ),
2287            // Proper fraction/nano conversion anywhere
2288            (
2289                ParsedDateTime {
2290                    year: Some(DateTimeFieldValue::new(1, 200_000_000)),
2291                    ..Default::default()
2292                },
2293                "1.2",
2294                "0.0",
2295                Year,
2296                1,
2297            ),
2298            (
2299                ParsedDateTime {
2300                    minute: Some(DateTimeFieldValue::new(1, 200_000_000)),
2301                    ..Default::default()
2302                },
2303                "1.2",
2304                "0.0",
2305                Minute,
2306                1,
2307            ),
2308            // Parse TimeUnit
2309            (
2310                ParsedDateTime {
2311                    month: Some(DateTimeFieldValue::new(3, 0)),
2312                    ..Default::default()
2313                },
2314                "3MONTHS",
2315                "0YEAR",
2316                Month,
2317                1,
2318            ),
2319            (
2320                ParsedDateTime {
2321                    month: Some(DateTimeFieldValue::new(1, 0)),
2322                    day: Some(DateTimeFieldValue::new(2, 0)),
2323                    hour: Some(DateTimeFieldValue::new(3, 0)),
2324                    ..Default::default()
2325                },
2326                "1MONTHS 2DAYS 3HOURS",
2327                "0YEAR 0YEAR 0YEAR",
2328                Month,
2329                1,
2330            ),
2331            (
2332                ParsedDateTime {
2333                    month: Some(DateTimeFieldValue::new(1, 0)),
2334                    day: Some(DateTimeFieldValue::new(2, 0)),
2335                    ..Default::default()
2336                },
2337                "1MONTHS-2",
2338                "0YEAR-0",
2339                Month,
2340                1,
2341            ),
2342        ];
2343        for test in test_cases.iter() {
2344            let mut pdt = ParsedDateTime::default();
2345            let mut actual = tokenize_time_str(test.1).unwrap();
2346            let expected = tokenize_time_str(test.2).unwrap();
2347
2348            fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.3, test.4).unwrap();
2349
2350            assert_eq!(pdt, test.0);
2351        }
2352    }
2353
2354    #[mz_ore::test]
2355    fn test_fill_pdt_from_tokens_errors() {
2356        use DateTimeField::*;
2357        let test_cases = [
2358            // Mismatched syntax
2359            (
2360                "1 2 3",
2361                "0-0 0",
2362                Year,
2363                1,
2364                "Invalid syntax at offset 1: provided Delim but expected Dash",
2365            ),
2366        ];
2367        for test in test_cases.iter() {
2368            let mut pdt = ParsedDateTime::default();
2369            let mut actual = tokenize_time_str(test.0).unwrap();
2370            let expected = tokenize_time_str(test.1).unwrap();
2371
2372            match fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.2, test.3) {
2373                Err(e) => assert_eq!(e.to_string(), test.4),
2374                Ok(_) => panic!("Test passed when expected to fail, generated {:?}", pdt),
2375            };
2376        }
2377    }
2378    #[mz_ore::test]
2379    #[should_panic(expected = "Cannot get smaller DateTimeField than MICROSECONDS")]
2380    fn test_fill_pdt_from_tokens_panic() {
2381        use DateTimeField::*;
2382        let test_cases = [
2383            // Mismatched syntax
2384            ("1 2", "0 0", Microseconds, 1),
2385        ];
2386        for test in test_cases.iter() {
2387            let mut pdt = ParsedDateTime::default();
2388            let mut actual = tokenize_time_str(test.0).unwrap();
2389            let expected = tokenize_time_str(test.1).unwrap();
2390
2391            if fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.2, test.3).is_ok() {
2392                panic!(
2393                    "test_fill_pdt_from_tokens_panic should have panicked. input {}\nformat {}\
2394                     \nDateTimeField {}\nGenerated ParsedDateTime {:?}",
2395                    test.0, test.1, test.2, pdt
2396                );
2397            };
2398        }
2399    }
2400
2401    #[mz_ore::test]
2402    fn test_fill_pdt_interval_pg() {
2403        use DateTimeField::*;
2404        let test_cases = [
2405            (
2406                ParsedDateTime {
2407                    year: Some(DateTimeFieldValue::new(2, 0)),
2408                    ..Default::default()
2409                },
2410                "2",
2411                Year,
2412            ),
2413            (
2414                ParsedDateTime {
2415                    month: Some(DateTimeFieldValue::new(2, 300_000_000)),
2416                    ..Default::default()
2417                },
2418                "2.3",
2419                Month,
2420            ),
2421            (
2422                ParsedDateTime {
2423                    day: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2424                    ..Default::default()
2425                },
2426                "-2.3",
2427                Day,
2428            ),
2429            (
2430                ParsedDateTime {
2431                    hour: Some(DateTimeFieldValue::new(2, 0)),
2432                    ..Default::default()
2433                },
2434                "2",
2435                Hour,
2436            ),
2437            (
2438                ParsedDateTime {
2439                    minute: Some(DateTimeFieldValue::new(2, 300_000_000)),
2440                    ..Default::default()
2441                },
2442                "2.3",
2443                Minute,
2444            ),
2445            (
2446                ParsedDateTime {
2447                    second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2448                    ..Default::default()
2449                },
2450                "-2.3",
2451                Second,
2452            ),
2453            (
2454                ParsedDateTime {
2455                    year: Some(DateTimeFieldValue::new(2, 0)),
2456                    ..Default::default()
2457                },
2458                "2year",
2459                Year,
2460            ),
2461            (
2462                ParsedDateTime {
2463                    month: Some(DateTimeFieldValue::new(2, 300_000_000)),
2464                    ..Default::default()
2465                },
2466                "2.3month",
2467                Month,
2468            ),
2469            (
2470                ParsedDateTime {
2471                    day: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2472                    ..Default::default()
2473                },
2474                "-2.3day",
2475                Day,
2476            ),
2477            (
2478                ParsedDateTime {
2479                    hour: Some(DateTimeFieldValue::new(2, 0)),
2480                    ..Default::default()
2481                },
2482                "2hour",
2483                Hour,
2484            ),
2485            (
2486                ParsedDateTime {
2487                    minute: Some(DateTimeFieldValue::new(2, 300_000_000)),
2488                    ..Default::default()
2489                },
2490                "2.3minute",
2491                Minute,
2492            ),
2493            (
2494                ParsedDateTime {
2495                    second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2496                    ..Default::default()
2497                },
2498                "-2.3second",
2499                Second,
2500            ),
2501            (
2502                ParsedDateTime {
2503                    second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2504                    ..Default::default()
2505                },
2506                ":::::::::-2.3second",
2507                Second,
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                    millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
2520                    ..Default::default()
2521                },
2522                "1.2milliseconds",
2523                Milliseconds,
2524            ),
2525            (
2526                ParsedDateTime {
2527                    microsecond: Some(DateTimeFieldValue::new(2, 300_000_000)),
2528                    ..Default::default()
2529                },
2530                "2.3microseconds",
2531                Microseconds,
2532            ),
2533            (
2534                ParsedDateTime {
2535                    millennium: Some(DateTimeFieldValue::new(4, 500_000_000)),
2536                    ..Default::default()
2537                },
2538                "4.5millennium",
2539                Millennium,
2540            ),
2541            (
2542                ParsedDateTime {
2543                    century: Some(DateTimeFieldValue::new(6, 700_000_000)),
2544                    ..Default::default()
2545                },
2546                "6.7century",
2547                Century,
2548            ),
2549            (
2550                ParsedDateTime {
2551                    decade: Some(DateTimeFieldValue::new(8, 900_000_000)),
2552                    ..Default::default()
2553                },
2554                "8.9decade",
2555                Decade,
2556            ),
2557        ];
2558        for test in test_cases.iter() {
2559            let mut pdt = ParsedDateTime::default();
2560            let mut actual = tokenize_time_str(test.1).unwrap();
2561            fill_pdt_interval_pg(&mut actual, test.2, &mut pdt).unwrap();
2562
2563            assert_eq!(pdt, test.0);
2564        }
2565    }
2566
2567    #[mz_ore::test]
2568    fn fill_pdt_interval_pg_errors() {
2569        use DateTimeField::*;
2570        let test_cases = [
2571            // Invalid syntax
2572            (
2573                "1.2.",
2574                Month,
2575                "Invalid syntax at offset 3: provided Dot but expected TimeUnit(Year)",
2576            ),
2577            // Running into this error means that determine_format_w_datetimefield
2578            // failed.
2579            (
2580                "1YEAR",
2581                Month,
2582                "Invalid syntax at offset 1: provided TimeUnit(YEAR) but expected TimeUnit(MONTH)",
2583            ),
2584        ];
2585        for test in test_cases.iter() {
2586            let mut pdt = ParsedDateTime::default();
2587            let mut actual = tokenize_time_str(test.0).unwrap();
2588            match fill_pdt_interval_pg(&mut actual, test.1, &mut pdt) {
2589                Err(e) => assert_eq!(e.to_string(), test.2),
2590                Ok(_) => panic!(
2591                    "Test passed when expected to fail, generated {:?}, expected error {}",
2592                    pdt, test.2,
2593                ),
2594            };
2595        }
2596    }
2597
2598    #[mz_ore::test]
2599    fn test_fill_pdt_interval_sql() {
2600        use DateTimeField::*;
2601        let test_cases = [
2602            (
2603                ParsedDateTime {
2604                    year: Some(DateTimeFieldValue::new(1, 0)),
2605                    month: Some(DateTimeFieldValue::new(2, 0)),
2606                    ..Default::default()
2607                },
2608                "1-2",
2609                Year,
2610            ),
2611            (
2612                ParsedDateTime {
2613                    hour: Some(DateTimeFieldValue::new(1, 0)),
2614                    minute: Some(DateTimeFieldValue::new(2, 0)),
2615                    second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2616                    ..Default::default()
2617                },
2618                "1:2:3.4",
2619                Hour,
2620            ),
2621            (
2622                ParsedDateTime {
2623                    hour: Some(DateTimeFieldValue::new(1, 0)),
2624                    minute: Some(DateTimeFieldValue::new(0, 0)),
2625                    second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2626                    ..Default::default()
2627                },
2628                "1::3.4",
2629                Hour,
2630            ),
2631            (
2632                ParsedDateTime {
2633                    hour: Some(DateTimeFieldValue::new(1, 0)),
2634                    minute: Some(DateTimeFieldValue::new(0, 0)),
2635                    second: Some(DateTimeFieldValue::new(0, 400_000_000)),
2636                    ..Default::default()
2637                },
2638                "1::.4",
2639                Hour,
2640            ),
2641            (
2642                ParsedDateTime {
2643                    hour: Some(DateTimeFieldValue::new(0, 0)),
2644                    minute: Some(DateTimeFieldValue::new(0, 0)),
2645                    second: Some(DateTimeFieldValue::new(0, 400_000_000)),
2646                    ..Default::default()
2647                },
2648                ".4",
2649                Second,
2650            ),
2651            (
2652                ParsedDateTime {
2653                    hour: Some(DateTimeFieldValue::new(0, 0)),
2654                    minute: Some(DateTimeFieldValue::new(1, 0)),
2655                    second: Some(DateTimeFieldValue::new(2, 300_000_000)),
2656                    ..Default::default()
2657                },
2658                "1:2.3",
2659                Minute,
2660            ),
2661            (
2662                ParsedDateTime {
2663                    year: Some(DateTimeFieldValue::new(-1, 0)),
2664                    month: Some(DateTimeFieldValue::new(-2, 0)),
2665                    ..Default::default()
2666                },
2667                "-1-2",
2668                Year,
2669            ),
2670            (
2671                ParsedDateTime {
2672                    hour: Some(DateTimeFieldValue::new(-1, 0)),
2673                    minute: Some(DateTimeFieldValue::new(-2, 0)),
2674                    second: Some(DateTimeFieldValue::new(-3, -400_000_000)),
2675                    ..Default::default()
2676                },
2677                "-1:2:3.4",
2678                Hour,
2679            ),
2680            (
2681                ParsedDateTime {
2682                    year: Some(DateTimeFieldValue::new(1, 0)),
2683                    month: Some(DateTimeFieldValue::new(2, 0)),
2684                    ..Default::default()
2685                },
2686                "+1-2",
2687                Year,
2688            ),
2689            (
2690                ParsedDateTime {
2691                    hour: Some(DateTimeFieldValue::new(1, 0)),
2692                    minute: Some(DateTimeFieldValue::new(2, 0)),
2693                    second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2694                    ..Default::default()
2695                },
2696                "+1:2:3.4",
2697                Hour,
2698            ),
2699            (
2700                ParsedDateTime {
2701                    year: Some(DateTimeFieldValue::new(-1, 0)),
2702                    month: Some(DateTimeFieldValue::new(-2, 0)),
2703                    ..Default::default()
2704                },
2705                "::::::-1-2",
2706                Year,
2707            ),
2708            (
2709                ParsedDateTime {
2710                    hour: Some(DateTimeFieldValue::new(-1, 0)),
2711                    minute: Some(DateTimeFieldValue::new(-2, 0)),
2712                    second: Some(DateTimeFieldValue::new(-3, -400_000_000)),
2713                    ..Default::default()
2714                },
2715                ":::::::-1:2:3.4",
2716                Hour,
2717            ),
2718        ];
2719        for test in test_cases.iter() {
2720            let mut pdt = ParsedDateTime::default();
2721            let mut actual = tokenize_time_str(test.1).unwrap();
2722            fill_pdt_interval_sql(&mut actual, test.2, &mut pdt).unwrap();
2723
2724            assert_eq!(pdt, test.0);
2725        }
2726    }
2727
2728    #[mz_ore::test]
2729    fn test_fill_pdt_interval_sql_errors() {
2730        use DateTimeField::*;
2731        let test_cases = [
2732            // Invalid syntax
2733            (
2734                "1.2",
2735                Year,
2736                "Invalid syntax at offset 1: provided Dot but expected Dash",
2737            ),
2738            (
2739                "1-2:3.4",
2740                Minute,
2741                "Invalid syntax at offset 1: provided Dash but expected Colon",
2742            ),
2743            (
2744                "1YEAR",
2745                Year,
2746                "Invalid syntax at offset 1: provided TimeUnit(Year) but expected Dash",
2747            ),
2748        ];
2749        for test in test_cases.iter() {
2750            let mut pdt = ParsedDateTime::default();
2751            let mut actual = tokenize_time_str(test.0).unwrap();
2752            match fill_pdt_interval_sql(&mut actual, test.1, &mut pdt) {
2753                Err(e) => assert_eq!(e.to_string(), test.2),
2754                Ok(_) => panic!("Test passed when expected to fail, generated {:?}", pdt),
2755            };
2756        }
2757    }
2758
2759    #[mz_ore::test]
2760    fn test_build_parsed_datetime_time() {
2761        run_test_build_parsed_datetime_time(
2762            "3:4:5.6",
2763            ParsedDateTime {
2764                hour: Some(DateTimeFieldValue::new(3, 0)),
2765                minute: Some(DateTimeFieldValue::new(4, 0)),
2766                second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2767                ..Default::default()
2768            },
2769        );
2770        run_test_build_parsed_datetime_time(
2771            "3:4",
2772            ParsedDateTime {
2773                hour: Some(DateTimeFieldValue::new(3, 0)),
2774                minute: Some(DateTimeFieldValue::new(4, 0)),
2775                ..Default::default()
2776            },
2777        );
2778        run_test_build_parsed_datetime_time(
2779            "3:4.5",
2780            ParsedDateTime {
2781                minute: Some(DateTimeFieldValue::new(3, 0)),
2782                second: Some(DateTimeFieldValue::new(4, 500_000_000)),
2783                ..Default::default()
2784            },
2785        );
2786        run_test_build_parsed_datetime_time(
2787            "0::4.5",
2788            ParsedDateTime {
2789                hour: Some(DateTimeFieldValue::new(0, 0)),
2790                second: Some(DateTimeFieldValue::new(4, 500_000_000)),
2791                ..Default::default()
2792            },
2793        );
2794        run_test_build_parsed_datetime_time(
2795            "0::.5",
2796            ParsedDateTime {
2797                hour: Some(DateTimeFieldValue::new(0, 0)),
2798                second: Some(DateTimeFieldValue::new(0, 500_000_000)),
2799                ..Default::default()
2800            },
2801        );
2802
2803        fn run_test_build_parsed_datetime_time(test: &str, res: ParsedDateTime) {
2804            assert_eq!(
2805                ParsedDateTime::build_parsed_datetime_time(test).unwrap(),
2806                res
2807            );
2808        }
2809    }
2810
2811    #[mz_ore::test]
2812    fn test_build_parsed_datetime_timestamp() {
2813        run_test_build_parsed_datetime_timestamp(
2814            "2000-01-02",
2815            ParsedDateTime {
2816                year: Some(DateTimeFieldValue::new(2000, 0)),
2817                month: Some(DateTimeFieldValue::new(1, 0)),
2818                day: Some(DateTimeFieldValue::new(2, 0)),
2819                ..Default::default()
2820            },
2821        );
2822        run_test_build_parsed_datetime_timestamp(
2823            "2000",
2824            ParsedDateTime {
2825                year: Some(DateTimeFieldValue::new(2000, 0)),
2826                ..Default::default()
2827            },
2828        );
2829        run_test_build_parsed_datetime_timestamp(
2830            "2000-1-",
2831            ParsedDateTime {
2832                year: Some(DateTimeFieldValue::new(2000, 0)),
2833                month: Some(DateTimeFieldValue::new(1, 0)),
2834                ..Default::default()
2835            },
2836        );
2837        run_test_build_parsed_datetime_timestamp(
2838            "2000-01-02 3:4:5.6",
2839            ParsedDateTime {
2840                year: Some(DateTimeFieldValue::new(2000, 0)),
2841                month: Some(DateTimeFieldValue::new(1, 0)),
2842                day: Some(DateTimeFieldValue::new(2, 0)),
2843                hour: Some(DateTimeFieldValue::new(3, 0)),
2844                minute: Some(DateTimeFieldValue::new(4, 0)),
2845                second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2846                ..Default::default()
2847            },
2848        );
2849        run_test_build_parsed_datetime_timestamp(
2850            "2000-01-02T3:4:5.6",
2851            ParsedDateTime {
2852                year: Some(DateTimeFieldValue::new(2000, 0)),
2853                month: Some(DateTimeFieldValue::new(1, 0)),
2854                day: Some(DateTimeFieldValue::new(2, 0)),
2855                hour: Some(DateTimeFieldValue::new(3, 0)),
2856                minute: Some(DateTimeFieldValue::new(4, 0)),
2857                second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2858                ..Default::default()
2859            },
2860        );
2861
2862        fn run_test_build_parsed_datetime_timestamp(test: &str, res: ParsedDateTime) {
2863            assert_eq!(
2864                ParsedDateTime::build_parsed_datetime_timestamp(test, CalendarEra::AD).unwrap(),
2865                res
2866            );
2867        }
2868    }
2869
2870    #[mz_ore::test]
2871    fn test_build_parsed_datetime_interval() {
2872        use DateTimeField::*;
2873        let test_cases = [
2874            (
2875                ParsedDateTime {
2876                    year: Some(DateTimeFieldValue::new(1, 0)),
2877                    month: Some(DateTimeFieldValue::new(2, 0)),
2878                    day: Some(DateTimeFieldValue::new(3, 0)),
2879                    hour: Some(DateTimeFieldValue::new(4, 0)),
2880                    minute: Some(DateTimeFieldValue::new(5, 0)),
2881                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2882                    ..Default::default()
2883                },
2884                "1-2 3 4:5:6.7",
2885                Second,
2886            ),
2887            (
2888                ParsedDateTime {
2889                    year: Some(DateTimeFieldValue::new(1, 0)),
2890                    month: Some(DateTimeFieldValue::new(2, 0)),
2891                    day: Some(DateTimeFieldValue::new(3, 0)),
2892                    hour: Some(DateTimeFieldValue::new(4, 0)),
2893                    minute: Some(DateTimeFieldValue::new(5, 0)),
2894                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2895                    ..Default::default()
2896                },
2897                "1 year 2 months 3 days 4 hours 5 minutes 6.7 seconds",
2898                Second,
2899            ),
2900            (
2901                ParsedDateTime {
2902                    second: Some(DateTimeFieldValue::new(1, 0)),
2903                    ..Default::default()
2904                },
2905                "1",
2906                Second,
2907            ),
2908            (
2909                ParsedDateTime {
2910                    day: Some(DateTimeFieldValue::new(1, 0)),
2911                    ..Default::default()
2912                },
2913                "1",
2914                Day,
2915            ),
2916            (
2917                ParsedDateTime {
2918                    month: Some(DateTimeFieldValue::new(1, 0)),
2919                    ..Default::default()
2920                },
2921                "1",
2922                Month,
2923            ),
2924            (
2925                ParsedDateTime {
2926                    hour: Some(DateTimeFieldValue::new(1, 0)),
2927                    minute: Some(DateTimeFieldValue::new(0, 0)),
2928                    second: Some(DateTimeFieldValue::new(0, 0)),
2929                    ..Default::default()
2930                },
2931                "1:",
2932                Second,
2933            ),
2934            (
2935                ParsedDateTime {
2936                    year: Some(DateTimeFieldValue::new(1, 0)),
2937                    month: Some(DateTimeFieldValue::new(0, 0)),
2938                    ..Default::default()
2939                },
2940                "1-",
2941                Second,
2942            ),
2943            (
2944                ParsedDateTime {
2945                    day: Some(DateTimeFieldValue::new(1, 0)),
2946                    hour: Some(DateTimeFieldValue::new(2, 0)),
2947                    minute: Some(DateTimeFieldValue::new(0, 0)),
2948                    second: Some(DateTimeFieldValue::new(0, 0)),
2949                    ..Default::default()
2950                },
2951                "1 2:",
2952                Second,
2953            ),
2954            (
2955                ParsedDateTime {
2956                    year: Some(DateTimeFieldValue::new(1, 0)),
2957                    month: Some(DateTimeFieldValue::new(2, 0)),
2958                    hour: Some(DateTimeFieldValue::new(3, 0)),
2959                    minute: Some(DateTimeFieldValue::new(4, 0)),
2960                    second: Some(DateTimeFieldValue::new(0, 0)),
2961                    ..Default::default()
2962                },
2963                "1-2 3:4",
2964                Second,
2965            ),
2966            (
2967                ParsedDateTime {
2968                    year: Some(DateTimeFieldValue::new(1, 0)),
2969                    month: Some(DateTimeFieldValue::new(0, 0)),
2970                    day: Some(DateTimeFieldValue::new(2, 0)),
2971                    hour: Some(DateTimeFieldValue::new(3, 0)),
2972                    minute: Some(DateTimeFieldValue::new(0, 0)),
2973                    second: Some(DateTimeFieldValue::new(0, 0)),
2974                    ..Default::default()
2975                },
2976                "1- 2 3:",
2977                Second,
2978            ),
2979            (
2980                ParsedDateTime {
2981                    year: Some(DateTimeFieldValue::new(5, 0)),
2982                    month: Some(DateTimeFieldValue::new(6, 0)),
2983                    hour: Some(DateTimeFieldValue::new(1, 0)),
2984                    minute: Some(DateTimeFieldValue::new(2, 0)),
2985                    second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2986                    ..Default::default()
2987                },
2988                "1:2:3.4 5-6",
2989                Second,
2990            ),
2991            (
2992                ParsedDateTime {
2993                    year: Some(DateTimeFieldValue::new(1, 0)),
2994                    month: Some(DateTimeFieldValue::new(2, 0)),
2995                    hour: Some(DateTimeFieldValue::new(3, 0)),
2996                    ..Default::default()
2997                },
2998                "1-2 3",
2999                Hour,
3000            ),
3001            (
3002                ParsedDateTime {
3003                    year: Some(DateTimeFieldValue::new(-1, 0)),
3004                    month: Some(DateTimeFieldValue::new(-2, 0)),
3005                    day: Some(DateTimeFieldValue::new(-3, 0)),
3006                    hour: Some(DateTimeFieldValue::new(-4, 0)),
3007                    minute: Some(DateTimeFieldValue::new(-5, 0)),
3008                    second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3009                    ..Default::default()
3010                },
3011                "-1-2 -3 -4:5:6.7",
3012                Second,
3013            ),
3014            (
3015                ParsedDateTime {
3016                    year: Some(DateTimeFieldValue::new(-1, 0)),
3017                    month: Some(DateTimeFieldValue::new(-2, 0)),
3018                    day: Some(DateTimeFieldValue::new(3, 0)),
3019                    hour: Some(DateTimeFieldValue::new(-4, 0)),
3020                    minute: Some(DateTimeFieldValue::new(-5, 0)),
3021                    second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3022                    ..Default::default()
3023                },
3024                "-1-2 3 -4:5:6.7",
3025                Second,
3026            ),
3027            (
3028                ParsedDateTime {
3029                    year: Some(DateTimeFieldValue::new(-1, 0)),
3030                    month: Some(DateTimeFieldValue::new(-2, 0)),
3031                    day: Some(DateTimeFieldValue::new(-3, 0)),
3032                    hour: Some(DateTimeFieldValue::new(4, 0)),
3033                    minute: Some(DateTimeFieldValue::new(0, 0)),
3034                    second: Some(DateTimeFieldValue::new(0, 500_000_000)),
3035                    ..Default::default()
3036                },
3037                "-1-2 -3 4::.5",
3038                Second,
3039            ),
3040            (
3041                ParsedDateTime {
3042                    hour: Some(DateTimeFieldValue::new(0, 0)),
3043                    minute: Some(DateTimeFieldValue::new(0, 0)),
3044                    second: Some(DateTimeFieldValue::new(-1, -270_000_000)),
3045                    ..Default::default()
3046                },
3047                "-::1.27",
3048                Second,
3049            ),
3050            (
3051                ParsedDateTime {
3052                    second: Some(DateTimeFieldValue::new(1, 270_000_000)),
3053                    ..Default::default()
3054                },
3055                ":::::1.27",
3056                Second,
3057            ),
3058            (
3059                ParsedDateTime {
3060                    year: Some(DateTimeFieldValue::new(1, 0)),
3061                    month: Some(DateTimeFieldValue::new(0, 0)),
3062                    day: Some(DateTimeFieldValue::new(2, 0)),
3063                    hour: Some(DateTimeFieldValue::new(3, 0)),
3064                    minute: Some(DateTimeFieldValue::new(0, 0)),
3065                    second: Some(DateTimeFieldValue::new(0, 0)),
3066                    ..Default::default()
3067                },
3068                ":::1- ::2 ::::3:",
3069                Second,
3070            ),
3071            (
3072                ParsedDateTime {
3073                    year: Some(DateTimeFieldValue::new(1, 0)),
3074                    month: Some(DateTimeFieldValue::new(2, 0)),
3075                    day: Some(DateTimeFieldValue::new(3, 0)),
3076                    hour: Some(DateTimeFieldValue::new(4, 0)),
3077                    minute: Some(DateTimeFieldValue::new(5, 0)),
3078                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3079                    ..Default::default()
3080                },
3081                "1 years 2 months 3 days 4 hours 5 minutes 6.7 seconds",
3082                Second,
3083            ),
3084            (
3085                ParsedDateTime {
3086                    year: Some(DateTimeFieldValue::new(1, 0)),
3087                    month: Some(DateTimeFieldValue::new(2, 0)),
3088                    day: Some(DateTimeFieldValue::new(3, 0)),
3089                    hour: Some(DateTimeFieldValue::new(4, 0)),
3090                    minute: Some(DateTimeFieldValue::new(5, 0)),
3091                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3092                    ..Default::default()
3093                },
3094                "1y 2mon 3d 4h 5m 6.7s",
3095                Second,
3096            ),
3097            (
3098                ParsedDateTime {
3099                    year: Some(DateTimeFieldValue::new(1, 0)),
3100                    month: Some(DateTimeFieldValue::new(2, 0)),
3101                    day: Some(DateTimeFieldValue::new(3, 0)),
3102                    hour: Some(DateTimeFieldValue::new(4, 0)),
3103                    minute: Some(DateTimeFieldValue::new(5, 0)),
3104                    second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3105                    ..Default::default()
3106                },
3107                "6.7 seconds 5 minutes 3 days 4 hours 1 year 2 month",
3108                Second,
3109            ),
3110            (
3111                ParsedDateTime {
3112                    year: Some(DateTimeFieldValue::new(-1, 0)),
3113                    month: Some(DateTimeFieldValue::new(2, 0)),
3114                    day: Some(DateTimeFieldValue::new(-3, 0)),
3115                    hour: Some(DateTimeFieldValue::new(4, 0)),
3116                    minute: Some(DateTimeFieldValue::new(5, 0)),
3117                    second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3118                    ..Default::default()
3119                },
3120                "-6.7 seconds 5 minutes -3 days 4 hours -1 year 2 month",
3121                Second,
3122            ),
3123            (
3124                ParsedDateTime {
3125                    year: Some(DateTimeFieldValue::new(1, 0)),
3126                    month: Some(DateTimeFieldValue::new(2, 300_000_000)),
3127                    day: Some(DateTimeFieldValue::new(4, 500_000_000)),
3128                    ..Default::default()
3129                },
3130                "1y 2.3mon 4.5d",
3131                Second,
3132            ),
3133            (
3134                ParsedDateTime {
3135                    year: Some(DateTimeFieldValue::new(-1, -200_000_000)),
3136                    month: Some(DateTimeFieldValue::new(2, 300_000_000)),
3137                    day: Some(DateTimeFieldValue::new(-3, -400_000_000)),
3138                    hour: Some(DateTimeFieldValue::new(4, 500_000_000)),
3139                    minute: Some(DateTimeFieldValue::new(5, 600_000_000)),
3140                    second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3141                    ..Default::default()
3142                },
3143                "-6.7 seconds 5.6 minutes -3.4 days 4.5 hours -1.2 year 2.3 month",
3144                Second,
3145            ),
3146            (
3147                ParsedDateTime {
3148                    day: Some(DateTimeFieldValue::new(1, 0)),
3149                    second: Some(DateTimeFieldValue::new(0, -270_000_000)),
3150                    ..Default::default()
3151                },
3152                "1 day -0.27 seconds",
3153                Second,
3154            ),
3155            (
3156                ParsedDateTime {
3157                    day: Some(DateTimeFieldValue::new(-1, 0)),
3158                    second: Some(DateTimeFieldValue::new(0, 270_000_000)),
3159                    ..Default::default()
3160                },
3161                "-1 day 0.27 seconds",
3162                Second,
3163            ),
3164            (
3165                ParsedDateTime {
3166                    year: Some(DateTimeFieldValue::new(10, 333_000_000)),
3167                    ..Default::default()
3168                },
3169                "10.333 years",
3170                Second,
3171            ),
3172            (
3173                ParsedDateTime {
3174                    year: Some(DateTimeFieldValue::new(10, 333_000_000)),
3175                    ..Default::default()
3176                },
3177                "10.333",
3178                Year,
3179            ),
3180            (
3181                ParsedDateTime {
3182                    year: Some(DateTimeFieldValue::new(1, 0)),
3183                    month: Some(DateTimeFieldValue::new(2, 0)),
3184                    day: Some(DateTimeFieldValue::new(5, 0)),
3185                    hour: Some(DateTimeFieldValue::new(3, 0)),
3186                    minute: Some(DateTimeFieldValue::new(4, 0)),
3187                    second: Some(DateTimeFieldValue::new(0, 0)),
3188                    ..Default::default()
3189                },
3190                "1-2 3:4 5 day",
3191                Second,
3192            ),
3193            (
3194                ParsedDateTime {
3195                    year: Some(DateTimeFieldValue::new(1, 0)),
3196                    month: Some(DateTimeFieldValue::new(2, 0)),
3197                    day: Some(DateTimeFieldValue::new(5, 0)),
3198                    hour: Some(DateTimeFieldValue::new(3, 0)),
3199                    minute: Some(DateTimeFieldValue::new(4, 0)),
3200                    second: Some(DateTimeFieldValue::new(0, 0)),
3201                    ..Default::default()
3202                },
3203                "5 day 3:4 1-2",
3204                Second,
3205            ),
3206            (
3207                ParsedDateTime {
3208                    year: Some(DateTimeFieldValue::new(1, 0)),
3209                    month: Some(DateTimeFieldValue::new(2, 0)),
3210                    day: Some(DateTimeFieldValue::new(5, 0)),
3211                    hour: Some(DateTimeFieldValue::new(3, 0)),
3212                    minute: Some(DateTimeFieldValue::new(4, 0)),
3213                    second: Some(DateTimeFieldValue::new(0, 0)),
3214                    ..Default::default()
3215                },
3216                "1-2 5 day 3:4",
3217                Second,
3218            ),
3219            (
3220                ParsedDateTime {
3221                    year: Some(DateTimeFieldValue::new(1, 0)),
3222                    day: Some(DateTimeFieldValue::new(2, 0)),
3223                    hour: Some(DateTimeFieldValue::new(3, 0)),
3224                    minute: Some(DateTimeFieldValue::new(4, 0)),
3225                    second: Some(DateTimeFieldValue::new(5, 600_000_000)),
3226                    ..Default::default()
3227                },
3228                "+1 year +2 days +3:4:5.6",
3229                Second,
3230            ),
3231            (
3232                ParsedDateTime {
3233                    year: Some(DateTimeFieldValue::new(1, 0)),
3234                    month: Some(DateTimeFieldValue::new(2, 0)),
3235                    ..Default::default()
3236                },
3237                "1-2",
3238                Month,
3239            ),
3240            (
3241                ParsedDateTime {
3242                    year: Some(DateTimeFieldValue::new(1, 0)),
3243                    month: Some(DateTimeFieldValue::new(2, 0)),
3244                    ..Default::default()
3245                },
3246                "1-2",
3247                Minute,
3248            ),
3249            (
3250                ParsedDateTime {
3251                    day: Some(DateTimeFieldValue::new(1, 999_999_999)),
3252                    ..Default::default()
3253                },
3254                "1.999999999999999999 days",
3255                Second,
3256            ),
3257            (
3258                ParsedDateTime {
3259                    millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
3260                    ..Default::default()
3261                },
3262                "1.2ms",
3263                Second,
3264            ),
3265            (
3266                ParsedDateTime {
3267                    millisecond: Some(DateTimeFieldValue::new(1, 0)),
3268                    ..Default::default()
3269                },
3270                "1ms",
3271                Second,
3272            ),
3273            (
3274                ParsedDateTime {
3275                    millisecond: Some(DateTimeFieldValue::new(2100, 0)),
3276                    ..Default::default()
3277                },
3278                "2100ms",
3279                Second,
3280            ),
3281            (
3282                ParsedDateTime {
3283                    hour: Some(DateTimeFieldValue::new(1, 0)),
3284                    millisecond: Some(DateTimeFieldValue::new(2, 0)),
3285                    ..Default::default()
3286                },
3287                "1h 2ms",
3288                Second,
3289            ),
3290            (
3291                ParsedDateTime {
3292                    millisecond: Some(DateTimeFieldValue::new(42, 900_000_000)),
3293                    ..Default::default()
3294                },
3295                "42.9 milliseconds",
3296                Second,
3297            ),
3298            (
3299                ParsedDateTime {
3300                    second: Some(DateTimeFieldValue::new(5, 0)),
3301                    millisecond: Some(DateTimeFieldValue::new(37, 660_000_000)),
3302                    ..Default::default()
3303                },
3304                "5.0 seconds 37.66 milliseconds",
3305                Second,
3306            ),
3307            (
3308                ParsedDateTime {
3309                    day: Some(DateTimeFieldValue::new(14, 0)),
3310                    millisecond: Some(DateTimeFieldValue::new(60, 0)),
3311                    ..Default::default()
3312                },
3313                "14 days 60 ms",
3314                Second,
3315            ),
3316            (
3317                ParsedDateTime {
3318                    microsecond: Some(DateTimeFieldValue::new(42, 900_000_000)),
3319                    ..Default::default()
3320                },
3321                "42.9 microseconds",
3322                Second,
3323            ),
3324            (
3325                ParsedDateTime {
3326                    second: Some(DateTimeFieldValue::new(5, 0)),
3327                    microsecond: Some(DateTimeFieldValue::new(37, 660_000_000)),
3328                    ..Default::default()
3329                },
3330                "5.0 seconds 37.66 microseconds",
3331                Second,
3332            ),
3333            (
3334                ParsedDateTime {
3335                    millennium: Some(DateTimeFieldValue::new(9, 800_000_000)),
3336                    ..Default::default()
3337                },
3338                "9.8 millenniums",
3339                Second,
3340            ),
3341            (
3342                ParsedDateTime {
3343                    century: Some(DateTimeFieldValue::new(7, 600_000_000)),
3344                    ..Default::default()
3345                },
3346                "7.6 centuries",
3347                Second,
3348            ),
3349            (
3350                ParsedDateTime {
3351                    decade: Some(DateTimeFieldValue::new(5, 400_000_000)),
3352                    ..Default::default()
3353                },
3354                "5.4 decades",
3355                Second,
3356            ),
3357            (
3358                ParsedDateTime {
3359                    year: Some(DateTimeFieldValue::new(1, 200_000_000)),
3360                    decade: Some(DateTimeFieldValue::new(4, 300_000_000)),
3361                    century: Some(DateTimeFieldValue::new(5, 600_000_000)),
3362                    millennium: Some(DateTimeFieldValue::new(8, 700_000_000)),
3363                    ..Default::default()
3364                },
3365                "8.7 mils 5.6 cent 4.3 decs 1.2 y",
3366                Second,
3367            ),
3368        ];
3369
3370        for test in test_cases.iter() {
3371            let actual =
3372                ParsedDateTime::build_parsed_datetime_interval(test.1, None, test.2).unwrap();
3373            if actual != test.0 {
3374                panic!(
3375                    "In test INTERVAL '{}' {}\n actual: {:?} \n expected: {:?}",
3376                    test.1, test.2, actual, test.0
3377                );
3378            }
3379        }
3380    }
3381
3382    #[mz_ore::test]
3383    fn test_build_parsed_datetime_interval_errors() {
3384        use DateTimeField::*;
3385        let test_cases = [
3386            ("1 year 2 years", Second, "YEAR field set twice"),
3387            ("1-2 3-4", Second, "YEAR or MONTH field set twice"),
3388            ("1-2 3 year", Second, "YEAR field set twice"),
3389            ("1-2 3", Month, "MONTH field set twice"),
3390            ("1-2 3:4 5", Second, "SECOND field set twice"),
3391            ("1:2:3.4 5-6 7", Year, "YEAR field set twice"),
3392            ("-:::::1.27", Second, "have unprocessed tokens 1.270000000"),
3393            (
3394                "-1 ::.27",
3395                Second,
3396                "Cannot determine format of all parts. Add explicit time components, e.g. \
3397                INTERVAL '1 day' or INTERVAL '1' DAY",
3398            ),
3399            ("1:2:3.4.5", Second, "have unprocessed tokens .500000000"),
3400            ("1+2:3.4", Second, "Cannot determine format of all parts"),
3401            ("1x2:3.4", Second, "unknown units x"),
3402            ("0 foo", Second, "unknown units foo"),
3403            ("1-2 3:4 5 second", Second, "SECOND field set twice"),
3404            (
3405                "1-2 5 second 3:4",
3406                Second,
3407                "HOUR, MINUTE, SECOND field set twice",
3408            ),
3409            (
3410                "1 2-3 4:5",
3411                Day,
3412                "Cannot determine format of all parts. Add explicit time components, e.g. \
3413                INTERVAL '1 day' or INTERVAL '1' DAY",
3414            ),
3415            (
3416                "9223372036854775808 months",
3417                Day,
3418                "Unable to parse value 9223372036854775808 as a number: number too large to fit in target type",
3419            ),
3420            (
3421                "-9223372036854775809 months",
3422                Day,
3423                "Unable to parse value 9223372036854775809 as a number: number too large to fit in target type",
3424            ),
3425            (
3426                "9223372036854775808 seconds",
3427                Day,
3428                "Unable to parse value 9223372036854775808 as a number: number too large to fit in target type",
3429            ),
3430            (
3431                "-9223372036854775809 seconds",
3432                Day,
3433                "Unable to parse value 9223372036854775809 as a number: number too large to fit in target type",
3434            ),
3435            (
3436                "1.234 second 5 ms",
3437                Second,
3438                "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3439            ),
3440            (
3441                "1.234 second 5 us",
3442                Second,
3443                "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3444            ),
3445            (
3446                "7 ms 4.321 second",
3447                Second,
3448                "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3449            ),
3450            (
3451                "7 us 4.321 second",
3452                Second,
3453                "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3454            ),
3455        ];
3456        for test in test_cases.iter() {
3457            match ParsedDateTime::build_parsed_datetime_interval(test.0, None, test.1) {
3458                Err(e) => assert_eq!(e.to_string(), test.2),
3459                Ok(pdt) => panic!(
3460                    "Test INTERVAL '{}' {} passed when expected to fail with {}, generated ParsedDateTime {:?}",
3461                    test.0, test.1, test.2, pdt,
3462                ),
3463            }
3464        }
3465    }
3466
3467    #[mz_ore::test]
3468    fn test_split_timestamp_string() {
3469        let test_cases = [
3470            (
3471                "1969-06-01 10:10:10.410 UTC",
3472                "1969-06-01 10:10:10.410",
3473                "UTC",
3474            ),
3475            (
3476                "1969-06-01 10:10:10.410+4:00",
3477                "1969-06-01 10:10:10.410",
3478                "+4:00",
3479            ),
3480            (
3481                "1969-06-01 10:10:10.410-4:00",
3482                "1969-06-01 10:10:10.410",
3483                "-4:00",
3484            ),
3485            ("1969-06-01 10:10:10.410", "1969-06-01 10:10:10.410", ""),
3486            ("1969-06-01 10:10:10.410+4", "1969-06-01 10:10:10.410", "+4"),
3487            ("1969-06-01 10:10:10.410-4", "1969-06-01 10:10:10.410", "-4"),
3488            ("1969-06-01 10:10:10+4:00", "1969-06-01 10:10:10", "+4:00"),
3489            ("1969-06-01 10:10:10-4:00", "1969-06-01 10:10:10", "-4:00"),
3490            ("1969-06-01 10:10:10 UTC", "1969-06-01 10:10:10", "UTC"),
3491            ("1969-06-01 10:10:10", "1969-06-01 10:10:10", ""),
3492            ("1969-06-01 10:10+4:00", "1969-06-01 10:10", "+4:00"),
3493            ("1969-06-01 10:10-4:00", "1969-06-01 10:10", "-4:00"),
3494            ("1969-06-01 10:10 UTC", "1969-06-01 10:10", "UTC"),
3495            ("1969-06-01 10:10", "1969-06-01 10:10", ""),
3496            ("1969-06-01 UTC", "1969-06-01", "UTC"),
3497            ("1969-06-01 +4:00", "1969-06-01", "+4:00"),
3498            ("1969-06-01 -4:00", "1969-06-01", "-4:00"),
3499            ("1969-06-01 +4", "1969-06-01", "+4"),
3500            ("1969-06-01 -4", "1969-06-01", "-4"),
3501            ("1969-06-01", "1969-06-01", ""),
3502            ("1969-06-01 10:10:10.410Z", "1969-06-01 10:10:10.410", "Z"),
3503            ("1969-06-01 10:10:10.410z", "1969-06-01 10:10:10.410", "z"),
3504            ("1969-06-01Z", "1969-06-01", "Z"),
3505            ("1969-06-01z", "1969-06-01", "z"),
3506            ("1969-06-01 10:10:10.410   ", "1969-06-01 10:10:10.410", ""),
3507            (
3508                "1969-06-01     10:10:10.410   ",
3509                "1969-06-01     10:10:10.410",
3510                "",
3511            ),
3512            ("   1969-06-01 10:10:10.412", "1969-06-01 10:10:10.412", ""),
3513            (
3514                "   1969-06-01 10:10:10.413   ",
3515                "1969-06-01 10:10:10.413",
3516                "",
3517            ),
3518            (
3519                "1969-06-01 10:10:10.410 +4:00",
3520                "1969-06-01 10:10:10.410",
3521                "+4:00",
3522            ),
3523            (
3524                "1969-06-01 10:10:10.410+4 :00",
3525                "1969-06-01 10:10:10.410",
3526                "+4 :00",
3527            ),
3528            (
3529                "1969-06-01 10:10:10.410      +4:00",
3530                "1969-06-01 10:10:10.410",
3531                "+4:00",
3532            ),
3533            (
3534                "1969-06-01 10:10:10.410+4:00     ",
3535                "1969-06-01 10:10:10.410",
3536                "+4:00",
3537            ),
3538            (
3539                "1969-06-01 10:10:10.410  Z  ",
3540                "1969-06-01 10:10:10.410",
3541                "Z",
3542            ),
3543            ("1969-06-01    +4  ", "1969-06-01", "+4"),
3544            ("1969-06-01   Z   ", "1969-06-01", "Z"),
3545        ];
3546
3547        for test in test_cases.iter() {
3548            let (ts, tz, era) = split_timestamp_string(test.0);
3549
3550            assert_eq!(ts, test.1);
3551            assert_eq!(tz, test.2);
3552            assert_eq!(era, CalendarEra::AD);
3553        }
3554    }
3555
3556    proptest! {
3557        #[mz_ore::test]
3558        #[cfg_attr(miri, ignore)] // slow, large amount of memory
3559        fn datetimeunits_serialization_roundtrip(expect in any::<DateTimeUnits>() ) {
3560            let actual = protobuf_roundtrip::<_, ProtoDateTimeUnits>(&expect);
3561            assert_ok!(actual);
3562            assert_eq!(actual.unwrap(), expect);
3563        }
3564    }
3565
3566    #[mz_ore::test]
3567    fn proptest_packed_naive_time_roundtrips() {
3568        let strat = add_arb_duration(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
3569        proptest!(|(time in strat)| {
3570            let packed = PackedNaiveTime::from_value(time);
3571            let rnd = packed.into_value();
3572            prop_assert_eq!(time, rnd);
3573        });
3574    }
3575
3576    #[mz_ore::test]
3577    fn proptest_packed_naive_time_sort_order() {
3578        let time = add_arb_duration(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
3579        let strat = proptest::collection::vec(time, 0..128);
3580        proptest!(|(mut times in strat)| {
3581            let mut packed: Vec<_> = times.iter().copied().map(PackedNaiveTime::from_value).collect();
3582
3583            times.sort();
3584            packed.sort();
3585
3586            for (time, packed) in times.into_iter().zip(packed.into_iter()) {
3587                let rnd = packed.into_value();
3588                prop_assert_eq!(time, rnd);
3589            }
3590        });
3591    }
3592}
3593
3594#[mz_ore::test]
3595fn test_parseddatetime_add_field() {
3596    use DateTimeField::*;
3597    let pdt_unit = ParsedDateTime {
3598        millennium: Some(DateTimeFieldValue::new(8, 0)),
3599        century: Some(DateTimeFieldValue::new(9, 0)),
3600        decade: Some(DateTimeFieldValue::new(10, 0)),
3601        year: Some(DateTimeFieldValue::new(1, 0)),
3602        month: Some(DateTimeFieldValue::new(2, 0)),
3603        day: Some(DateTimeFieldValue::new(2, 0)),
3604        hour: Some(DateTimeFieldValue::new(3, 0)),
3605        minute: Some(DateTimeFieldValue::new(4, 0)),
3606        second: Some(DateTimeFieldValue::new(5, 0)),
3607        millisecond: Some(DateTimeFieldValue::new(6, 0)),
3608        microsecond: Some(DateTimeFieldValue::new(7, 0)),
3609        ..Default::default()
3610    };
3611
3612    let pdt_frac = ParsedDateTime {
3613        millennium: Some(DateTimeFieldValue::new(8, 555_555_555)),
3614        century: Some(DateTimeFieldValue::new(9, 555_555_555)),
3615        decade: Some(DateTimeFieldValue::new(10, 555_555_555)),
3616        year: Some(DateTimeFieldValue::new(1, 555_555_555)),
3617        month: Some(DateTimeFieldValue::new(2, 555_555_555)),
3618        day: Some(DateTimeFieldValue::new(2, 555_555_555)),
3619        hour: Some(DateTimeFieldValue::new(3, 555_555_555)),
3620        minute: Some(DateTimeFieldValue::new(4, 555_555_555)),
3621        second: Some(DateTimeFieldValue::new(5, 555_555_555)),
3622        millisecond: Some(DateTimeFieldValue::new(6, 555_555_555)),
3623        microsecond: Some(DateTimeFieldValue::new(7, 555_555_555)),
3624        ..Default::default()
3625    };
3626
3627    let pdt_frac_neg = ParsedDateTime {
3628        millennium: Some(DateTimeFieldValue::new(-8, -555_555_555)),
3629        century: Some(DateTimeFieldValue::new(-9, -555_555_555)),
3630        decade: Some(DateTimeFieldValue::new(-10, -555_555_555)),
3631        year: Some(DateTimeFieldValue::new(-1, -555_555_555)),
3632        month: Some(DateTimeFieldValue::new(-2, -555_555_555)),
3633        day: Some(DateTimeFieldValue::new(-2, -555_555_555)),
3634        hour: Some(DateTimeFieldValue::new(-3, -555_555_555)),
3635        minute: Some(DateTimeFieldValue::new(-4, -555_555_555)),
3636        second: Some(DateTimeFieldValue::new(-5, -555_555_555)),
3637        millisecond: Some(DateTimeFieldValue::new(-6, -555_555_555)),
3638        microsecond: Some(DateTimeFieldValue::new(-7, -555_555_555)),
3639        ..Default::default()
3640    };
3641
3642    let pdt_s_rollover = ParsedDateTime {
3643        millisecond: Some(DateTimeFieldValue::new(1002, 666_666_666)),
3644        microsecond: Some(DateTimeFieldValue::new(1000003, 777_777_777)),
3645        ..Default::default()
3646    };
3647
3648    run_test_parseddatetime_add_field(pdt_unit.clone(), Millennium, (8 * 12 * 1_000, 0, 0));
3649    run_test_parseddatetime_add_field(pdt_unit.clone(), Century, (9 * 12 * 100, 0, 0));
3650    run_test_parseddatetime_add_field(pdt_unit.clone(), Decade, (10 * 12 * 10, 0, 0));
3651    run_test_parseddatetime_add_field(pdt_unit.clone(), Year, (12, 0, 0));
3652    run_test_parseddatetime_add_field(pdt_unit.clone(), Month, (2, 0, 0));
3653    run_test_parseddatetime_add_field(pdt_unit.clone(), Day, (0, 2, 0));
3654    run_test_parseddatetime_add_field(pdt_unit.clone(), Hour, (0, 0, 3 * 60 * 60 * 1_000_000));
3655    run_test_parseddatetime_add_field(pdt_unit.clone(), Minute, (0, 0, 4 * 60 * 1_000_000));
3656    run_test_parseddatetime_add_field(pdt_unit.clone(), Second, (0, 0, 5 * 1_000_000));
3657    run_test_parseddatetime_add_field(pdt_unit.clone(), Milliseconds, (0, 0, 6 * 1_000));
3658    run_test_parseddatetime_add_field(pdt_unit, Microseconds, (0, 0, 7));
3659    run_test_parseddatetime_add_field(pdt_frac.clone(), Millennium, (102_666, 0, 0));
3660    run_test_parseddatetime_add_field(pdt_frac.clone(), Century, (11466, 0, 0));
3661    run_test_parseddatetime_add_field(pdt_frac.clone(), Decade, (1266, 0, 0));
3662    run_test_parseddatetime_add_field(pdt_frac.clone(), Year, (18, 0, 0));
3663    run_test_parseddatetime_add_field(
3664        pdt_frac.clone(),
3665        Month,
3666        (
3667            2,
3668            16,
3669            // 15:59:59.99856
3670            (15 * 60 * 60 * 1_000_000) + (59 * 60 * 1_000_000) + (59 * 1_000_000) + 998_560,
3671        ),
3672    );
3673    run_test_parseddatetime_add_field(
3674        pdt_frac.clone(),
3675        Day,
3676        (
3677            0,
3678            2,
3679            // 13:19:59.999952
3680            (13 * 60 * 60 * 1_000_000) + (19 * 60 * 1_000_000) + (59 * 1_000_000) + 999_952,
3681        ),
3682    );
3683    run_test_parseddatetime_add_field(
3684        pdt_frac.clone(),
3685        Hour,
3686        (
3687            0,
3688            0,
3689            // 03:33:19.999998
3690            (3 * 60 * 60 * 1_000_000) + (33 * 60 * 1_000_000) + (19 * 1_000_000) + 999_998,
3691        ),
3692    );
3693    run_test_parseddatetime_add_field(
3694        pdt_frac.clone(),
3695        Minute,
3696        (
3697            0,
3698            0,
3699            // 00:04:33.333333
3700            (4 * 60 * 1_000_000) + (33 * 1_000_000) + 333_333,
3701        ),
3702    );
3703    run_test_parseddatetime_add_field(
3704        pdt_frac.clone(),
3705        Second,
3706        (
3707            0,
3708            0,
3709            // 00:00:05.555556
3710            (5 * 1_000_000) + 555_556,
3711        ),
3712    );
3713    run_test_parseddatetime_add_field(
3714        pdt_frac.clone(),
3715        Milliseconds,
3716        (
3717            0, 0, // 00:00:00.006556
3718            6_556,
3719        ),
3720    );
3721    run_test_parseddatetime_add_field(
3722        pdt_frac,
3723        Microseconds,
3724        (
3725            0, 0, // 00:00:00.000008
3726            8,
3727        ),
3728    );
3729    run_test_parseddatetime_add_field(pdt_frac_neg.clone(), Year, (-18, 0, 0));
3730    run_test_parseddatetime_add_field(
3731        pdt_frac_neg.clone(),
3732        Month,
3733        (
3734            -2,
3735            -16,
3736            // -15:59:59.99856
3737            (-15 * 60 * 60 * 1_000_000) + (-59 * 60 * 1_000_000) + (-59 * 1_000_000) + -998_560,
3738        ),
3739    );
3740    run_test_parseddatetime_add_field(
3741        pdt_frac_neg.clone(),
3742        Day,
3743        (
3744            0,
3745            -2,
3746            // 13:19:59.999952
3747            (-13 * 60 * 60 * 1_000_000) + (-19 * 60 * 1_000_000) + (-59 * 1_000_000) + -999_952,
3748        ),
3749    );
3750    run_test_parseddatetime_add_field(
3751        pdt_frac_neg.clone(),
3752        Hour,
3753        (
3754            0,
3755            0,
3756            // -03:33:19.999998
3757            (-3 * 60 * 60 * 1_000_000) + (-33 * 60 * 1_000_000) + (-19 * 1_000_000) + -999_998,
3758        ),
3759    );
3760    run_test_parseddatetime_add_field(
3761        pdt_frac_neg.clone(),
3762        Minute,
3763        (
3764            0,
3765            0,
3766            // -00:04:33.333333
3767            (-4 * 60 * 1_000_000) + (-33 * 1_000_000) + -333_333,
3768        ),
3769    );
3770    run_test_parseddatetime_add_field(
3771        pdt_frac_neg.clone(),
3772        Second,
3773        (
3774            0,
3775            0,
3776            // -00:00:05.555556
3777            (-5 * 1_000_000) + -555_556,
3778        ),
3779    );
3780    run_test_parseddatetime_add_field(
3781        pdt_frac_neg.clone(),
3782        Milliseconds,
3783        (
3784            0, 0, // -00:00:00.006556
3785            -6_556,
3786        ),
3787    );
3788    run_test_parseddatetime_add_field(
3789        pdt_frac_neg,
3790        Microseconds,
3791        (
3792            0, 0, // -00:00:00.000008
3793            -8,
3794        ),
3795    );
3796    run_test_parseddatetime_add_field(
3797        pdt_s_rollover.clone(),
3798        Milliseconds,
3799        (
3800            0,
3801            0, // 00:00:01.002667
3802            (1 * 1_000_000) + 2_667,
3803        ),
3804    );
3805    run_test_parseddatetime_add_field(
3806        pdt_s_rollover,
3807        Microseconds,
3808        (
3809            0,
3810            0, // 00:00:01.000004
3811            (1 * 1_000_000) + 4,
3812        ),
3813    );
3814
3815    fn run_test_parseddatetime_add_field(
3816        pdt: ParsedDateTime,
3817        f: DateTimeField,
3818        expected: (i32, i32, i64),
3819    ) {
3820        let mut res = (0, 0, 0);
3821
3822        pdt.add_field(f, &mut res.0, &mut res.1, &mut res.2)
3823            .unwrap();
3824
3825        if res.0 != expected.0 || res.1 != expected.1 || res.2 != expected.2 {
3826            panic!(
3827                "test_parseddatetime_add_field failed \n actual: {:?} \n expected: {:?}",
3828                res, expected
3829            );
3830        }
3831    }
3832}
3833
3834#[mz_ore::test]
3835fn test_parseddatetime_compute_interval() {
3836    run_test_parseddatetime_compute_interval(
3837        ParsedDateTime {
3838            year: Some(DateTimeFieldValue::new(1, 0)),
3839            month: Some(DateTimeFieldValue::new(1, 0)),
3840            ..Default::default()
3841        },
3842        Interval {
3843            months: 13,
3844            ..Default::default()
3845        },
3846    );
3847    run_test_parseddatetime_compute_interval(
3848        ParsedDateTime {
3849            year: Some(DateTimeFieldValue::new(1, 0)),
3850            month: Some(DateTimeFieldValue::new(-1, 0)),
3851            ..Default::default()
3852        },
3853        Interval {
3854            months: 11,
3855            ..Default::default()
3856        },
3857    );
3858    run_test_parseddatetime_compute_interval(
3859        ParsedDateTime {
3860            year: Some(DateTimeFieldValue::new(-1, 0)),
3861            month: Some(DateTimeFieldValue::new(1, 0)),
3862            ..Default::default()
3863        },
3864        Interval {
3865            months: -11,
3866            ..Default::default()
3867        },
3868    );
3869    run_test_parseddatetime_compute_interval(
3870        ParsedDateTime {
3871            day: Some(DateTimeFieldValue::new(1, 0)),
3872            hour: Some(DateTimeFieldValue::new(-2, 0)),
3873            minute: Some(DateTimeFieldValue::new(-3, 0)),
3874            second: Some(DateTimeFieldValue::new(-4, -500_000_000)),
3875            ..Default::default()
3876        },
3877        // 1 day -2:03:04.5
3878        Interval::new(
3879            0,
3880            1,
3881            (-2 * 60 * 60 * 1_000_000) + (-3 * 60 * 1_000_000) + (-4 * 1_000_000) + -500_000,
3882        ),
3883    );
3884    run_test_parseddatetime_compute_interval(
3885        ParsedDateTime {
3886            day: Some(DateTimeFieldValue::new(-1, 0)),
3887            hour: Some(DateTimeFieldValue::new(2, 0)),
3888            minute: Some(DateTimeFieldValue::new(3, 0)),
3889            second: Some(DateTimeFieldValue::new(4, 500_000_000)),
3890            ..Default::default()
3891        },
3892        // -1 day 02:03:04.5
3893        Interval::new(
3894            0,
3895            -1,
3896            (2 * 60 * 60 * 1_000_000) + (3 * 60 * 1_000_000) + (4 * 1_000_000) + 500_000,
3897        ),
3898    );
3899    run_test_parseddatetime_compute_interval(
3900        ParsedDateTime {
3901            day: Some(DateTimeFieldValue::new(1, 0)),
3902            second: Some(DateTimeFieldValue::new(0, -270_000_000)),
3903            ..Default::default()
3904        },
3905        // 1 day -00:00:00.27
3906        Interval::new(0, 1, -270_000),
3907    );
3908    run_test_parseddatetime_compute_interval(
3909        ParsedDateTime {
3910            day: Some(DateTimeFieldValue::new(-1, 0)),
3911            second: Some(DateTimeFieldValue::new(0, 270_000_000)),
3912            ..Default::default()
3913        },
3914        // -1 day 00:00:00.27
3915        Interval::new(0, -1, 270_000),
3916    );
3917    run_test_parseddatetime_compute_interval(
3918        ParsedDateTime {
3919            year: Some(DateTimeFieldValue::new(-1, -555_555_555)),
3920            month: Some(DateTimeFieldValue::new(2, 555_555_555)),
3921            day: Some(DateTimeFieldValue::new(-3, -555_555_555)),
3922            hour: Some(DateTimeFieldValue::new(4, 555_555_555)),
3923            minute: Some(DateTimeFieldValue::new(-5, -555_555_555)),
3924            second: Some(DateTimeFieldValue::new(6, 555_555_555)),
3925            ..Default::default()
3926        },
3927        // -1 year -4 months +13 days +07:07:53.220829
3928        Interval::new(
3929            -16,
3930            13,
3931            (7 * 60 * 60 * 1_000_000) + (7 * 60 * 1_000_000) + (53 * 1_000_000) + 220_829,
3932        ),
3933    );
3934    run_test_parseddatetime_compute_interval(
3935        ParsedDateTime {
3936            second: Some(DateTimeFieldValue::new(1, 0)),
3937            millisecond: Some(DateTimeFieldValue::new(2_003, 0)),
3938            ..Default::default()
3939        },
3940        // 00:00:03.003
3941        Interval::new(0, 0, (3 * 1_000_000) + 3_000),
3942    );
3943    run_test_parseddatetime_compute_interval(
3944        ParsedDateTime {
3945            second: Some(DateTimeFieldValue::new(1, 0)),
3946            microsecond: Some(DateTimeFieldValue::new(2_000_003, 0)),
3947            ..Default::default()
3948        },
3949        // 00:00:03.000003
3950        Interval::new(0, 0, (3 * 1_000_000) + 3),
3951    );
3952    run_test_parseddatetime_compute_interval(
3953        ParsedDateTime {
3954            millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
3955            microsecond: Some(DateTimeFieldValue::new(3, 400_000_000)),
3956            ..Default::default()
3957        },
3958        // 00:00:00.0012034
3959        Interval::new(0, 0, 1_203),
3960    );
3961    run_test_parseddatetime_compute_interval(
3962        ParsedDateTime {
3963            millennium: Some(DateTimeFieldValue::new(1, 0)),
3964            century: Some(DateTimeFieldValue::new(2, 0)),
3965            decade: Some(DateTimeFieldValue::new(3, 0)),
3966            year: Some(DateTimeFieldValue::new(4, 0)),
3967            ..Default::default()
3968        },
3969        // 1234 years
3970        Interval::new(1234 * 12, 0, 0),
3971    );
3972
3973    fn run_test_parseddatetime_compute_interval(pdt: ParsedDateTime, expected: Interval) {
3974        let actual = pdt.compute_interval().unwrap();
3975
3976        if actual != expected {
3977            panic!(
3978                "test_interval_compute_interval failed\n input {:?}\nactual {:?}\nexpected {:?}",
3979                pdt, actual, expected
3980            )
3981        }
3982    }
3983}