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