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