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