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