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